<# .SYNOPSIS Exports Active Directory OUs to CSV, with their path, depth, GPO links and object counts. .DESCRIPTION Reads every OU under a search base and turns each one into a flat, spreadsheet-friendly row: name, readable path, depth, parent, whether it's protected from accidental deletion, how many GPOs are linked to it, and (optionally) how many users, computers and groups sit directly inside it. Writes a CSV and can return the objects too. .PARAMETER SearchBase Where to start. Defaults to the root of the domain. .PARAMETER CsvPath Output file. Defaults to ad-ous-.csv in the current folder. .PARAMETER IncludeObjectCount Also count users, computers and groups directly in each OU. Slower on big directories. .PARAMETER Server Domain or domain controller to query. .PARAMETER PassThru Return the rows as objects as well as writing the CSV. .EXAMPLE .\Export-ADOrganizationalUnit.ps1 .EXAMPLE .\Export-ADOrganizationalUnit.ps1 -SearchBase 'OU=Branches,DC=contoso,DC=com' -IncludeObjectCount -PassThru | Where-Object Computers -eq 0 #> [CmdletBinding()] param( [string]$SearchBase, [string]$CsvPath = (Join-Path (Get-Location) ('ad-ous-{0:yyyy-MM-dd}.csv' -f (Get-Date))), [switch]$IncludeObjectCount, [string]$Server, [switch]$PassThru ) $ErrorActionPreference = 'Stop' Import-Module ActiveDirectory $ad = @{} if ($Server) { $ad.Server = $Server } if (-not $SearchBase) { $SearchBase = (Get-ADDomain @ad).DistinguishedName } $props = 'CanonicalName', 'Description', 'gPLink', 'ProtectedFromAccidentalDeletion', 'whenCreated', 'ManagedBy' $ous = Get-ADOrganizationalUnit -Filter * -SearchBase $SearchBase -SearchScope Subtree -Properties $props @ad Write-Verbose "Found $(@($ous).Count) OUs under $SearchBase" $rows = foreach ($ou in $ous) { # CanonicalName is contoso.com/Corp/Devices/Laptops; drop the domain part for a readable path. # A slash inside an OU name comes through escaped (\/), so don't split on those. $parts = @($ou.CanonicalName -split '(?