Public/Get-UserOU.ps1
function Get-UserOU { <# .SYNOPSIS Returns a user's parent OU/container in multiple useful formats. .DESCRIPTION Looks up an AD user and derives the parent OU/container they live in. Outputs a structured object with DistinguishedName, CanonicalPath, LDAPPath, ADDrivePath, ContainerType, etc. Accepts pipeline input. .PARAMETER User The user identity (sAMAccountName, UPN, DN, GUID, SID). Accepts pipeline input by value or by property name. .PARAMETER Server Optional domain controller to query (passed to Get-ADUser -Server). #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('Username','SamAccountName','UserPrincipalName','Identity','UPN')] [string]$User, [Parameter()] [string]$Server ) begin { if (-not (Get-Command -Name Get-ADUser -ErrorAction SilentlyContinue)) { try { Import-Module ActiveDirectory -ErrorAction Stop } catch { throw "ActiveDirectory module not available. Install RSAT or import the module, then retry." } } function Convert-DNToCanonical { param([Parameter(Mandatory)][string]$Dn) $parts = $Dn -split ',' $domainPart = $parts | Where-Object { $_ -like 'DC=*' } $domain = ( $domainPart | ForEach-Object { $_.Substring(3) } ) -join '.' $nonDomain = $parts | Where-Object { $_ -notlike 'DC=*' } | ForEach-Object { ($_ -split '=',2)[1] } if ($nonDomain.Count -gt 0) { $rev = @($nonDomain) [array]::Reverse($rev) if ([string]::IsNullOrWhiteSpace($domain)) { ($rev -join '/') } else { "$domain/$($rev -join '/')" } } else { $domain } } } process { try { $getParams = @{ Identity = $User; ErrorAction = 'Stop' } if ($Server) { $getParams.Server = $Server } $u = Get-ADUser @getParams -Properties DistinguishedName, CanonicalName, SamAccountName, UserPrincipalName $userDN = $u.DistinguishedName if (-not $userDN) { Write-Error "No DistinguishedName returned for '$User'." -ErrorAction Continue return } # Parent container DN (everything after the user's CN=... segment) $parentDN = ($userDN -split ',',2)[1] # Container type and leaf name (e.g., OU=Corp-Staff or CN=Users) $leafRDN = $parentDN.Split(',')[0] if ($leafRDN -like 'OU=*') { $containerType = 'OU' } else { $containerType = 'CN' } $leafName = ($leafRDN -split '=',2)[1] # Domain pieces (FIX: wrap pipelines in parentheses before -join) $domainDN = ( ($parentDN -split ',') | Where-Object { $_ -like 'DC=*' } ) -join ',' $domainName = ( ($parentDN -split ',') | Where-Object { $_ -like 'DC=*' } | ForEach-Object { $_.Substring(3) } ) -join '.' # Canonical form of the parent container $canonicalParent = Convert-DNToCanonical -Dn $parentDN [pscustomobject]@{ User = $u.SamAccountName UserPrincipalName = $u.UserPrincipalName UserDistinguishedName = $userDN ContainerType = $containerType LeafContainerName = $leafName DistinguishedName = $parentDN CanonicalPath = $canonicalParent LDAPPath = "LDAP://$parentDN" ADDrivePath = "AD:\$parentDN" Domain = $domainName DomainDN = $domainDN } } catch { Write-Error "Get-UserOU failed for '$User': $($_.Exception.Message)" -ErrorAction Continue } } } |