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 (OU/Container DN) - CanonicalPath (domain.tld/Top/Child) - LDAPPath (LDAP://OU=Child,OU=Top,DC=domain,DC=tld) - ADDrivePath (AD:\OU=Child,OU=Top,DC=domain,DC=tld) - ContainerType ('OU' or 'CN') - LeafContainerName (e.g., 'Users' or 'Corp-Staff') - Domain, DomainDN, plus user identifiers for convenience .PARAMETER User The user identity (sAMAccountName, UPN, DN, GUID, SID). Accepts pipeline input by value or by property name (User, Username, SamAccountName, UserPrincipalName, Identity, UPN). .PARAMETER Server Optional domain controller to query (passed to Get-ADUser -Server). .EXAMPLE Get-UserOU -User "cathy.chen" .EXAMPLE 'cathy.chen','alex.jones' | Get-UserOU .EXAMPLE [pscustomobject]@{ Username='cathy.chen' }, [pscustomobject]@{ UPN='alex.jones@contoso.com' } | Get-UserOU .OUTPUTS PSCustomObject (one per input user), suitable for piping/Export-Csv/Select-Object, etc. #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('Username','SamAccountName','UserPrincipalName','Identity','UPN')] [string]$User, [Parameter()] [string]$Server ) begin { # Ensure AD cmdlets are available 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] $containerType = ($leafRDN -like 'OU=*') ? 'OU' : 'CN' $leafName = ($leafRDN -split '=',2)[1] # Domain pieces $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 # Output object [pscustomobject]@{ User = $u.SamAccountName UserPrincipalName = $u.UserPrincipalName UserDistinguishedName = $userDN ContainerType = $containerType # 'OU' or 'CN' LeafContainerName = $leafName # e.g., 'Users' or 'Corp-Staff' DistinguishedName = $parentDN # OU=...,DC=... CanonicalPath = $canonicalParent # domain.tld/Top/Child LDAPPath = "LDAP://$parentDN" # LDAP://OU=...,DC=... ADDrivePath = "AD:\$parentDN" # AD:\OU=...,DC=... Domain = $domainName # contoso.com DomainDN = $domainDN # DC=contoso,DC=com } } catch { Write-Error "Get-UserOU failed for '$User': $($_.Exception.Message)" -ErrorAction Continue } } } |