Public/AD/Get-ADOrgUnitsForProcessing.ps1
|
<#
.SYNOPSIS Returns missing AD OUs sorted so parents come before children. .DESCRIPTION Collects every OU path needed by active users, expands each path to include all ancestor OUs, filters out ones that already exist, then sorts by depth so parents are always created before their children. .PARAMETER UserList Full user list from the identity database. Only active users are processed. .PARAMETER UserRootOU Root OU for users. Retained for consistency but not directly used since ancestor expansion covers it automatically. .PARAMETER CurrentOrgUnits OUs that already exist in AD, used to filter out OUs that don't need creating. #> function Get-ADOrgUnitsForProcessing { [CmdletBinding()] param ( [Parameter(Mandatory = $true)] $UserList, [Parameter(Mandatory = $true)] $UserRootOU, [Parameter(Mandatory = $true)] $CurrentOrgUnits ) # Collect every OU path referenced by active users (active OU + trash OU) $OUList = @() foreach ($item in $UserList | Where-Object {$_.IDBActive -eq $true}) { $OUList += $item.ADOrganizationalUnit $OUList += $item.ADOrganizationalUnitTrash } # Expand each OU to include all ancestor paths. # AD DNs are leaf-first, so "OU=Child,OU=Parent,DC=domain,DC=local" expands to: # OU=Parent,DC=domain,DC=local # OU=Child,OU=Parent,DC=domain,DC=local # Using a Generic List instead of += on arrays for better performance. $OUListExpanded = [System.Collections.Generic.List[string]]::new() foreach ($ou in $OUList) { $components = $ou -split ',' $ouComponents = $components | Where-Object { $_ -match '^OU=' } $baseDC = $components | Where-Object { $_ -notmatch '^OU=' } for ($i = $ouComponents.Count; $i -ge 1; $i--) { $ancestor = $ouComponents[($ouComponents.Count - $i)..($ouComponents.Count - 1)] $OUListExpanded.Add(($ancestor + $baseDC) -join ',') } } # Use a HashSet for O(1) lookups when filtering out existing OUs $currentOUSet = [System.Collections.Generic.HashSet[string]]::new( [string[]]$CurrentOrgUnits, [System.StringComparer]::OrdinalIgnoreCase ) # Deduplicate, remove existing, sort parents before children $OrgUnitsForProcessing = $OUListExpanded | Sort-Object -Unique | Where-Object { -not $currentOUSet.Contains($_) } | Sort-Object { ($_ -split ',OU=').Count } foreach ($item in $OrgUnitsForProcessing) { Write-Log -Message "AD: Adding Org Unit to Process List: Create: $($item)" } return $OrgUnitsForProcessing } |