src/Private/Test-AccountExcluded.ps1
|
function Test-AccountExcluded { <# .SYNOPSIS True when an account's distinguished name falls under one of the excluded OUs. .DESCRIPTION Lets a customer suppress deliberately-licensed accounts (shared mailboxes, litigation-hold or forwarding mailboxes) so they don't resurface as "reclaim candidates" on every scan. Each -ExcludeOu value is matched as a contiguous run of whole RDN components in the DN, case-insensitively. So both a full OU path ('OU=Shared Mailboxes,DC=contoso,DC=com') and a single component ('OU=Shared Mailboxes') exclude every account in that OU's subtree. Both the DN and each excluded value are split on UNescaped commas (a comma inside a value is written '\,' in a DN and must not split a component), so a CN that literally contains the text 'OU=...' is never mistaken for an organizational unit, and stray leading/trailing/empty components (e.g. a copied trailing comma) are dropped rather than silently defeating the match. .OUTPUTS [bool] #> [CmdletBinding()] param( [string] $DistinguishedName, [string[]] $ExcludeOu ) if (-not $DistinguishedName -or -not $ExcludeOu) { return $false } # Split a DN into RDN components on commas that are NOT escaped (\,), then trim, drop empties, # and lower-case for comparison. function _rdns([string] $dn) { @([regex]::Split($dn, '(?<!\\),') | ForEach-Object { $_.Trim() } | Where-Object { $_ } | ForEach-Object { $_.ToLowerInvariant() }) } # @() at the call site keeps a single-component result an array (PowerShell unrolls a returned # one-element collection to a scalar, which would break .Count under Set-StrictMode). $dnParts = @(_rdns $DistinguishedName) foreach ($ou in $ExcludeOu) { if (-not $ou) { continue } $ouParts = @(_rdns $ou) if (-not $ouParts.Count) { continue } # Does the excluded OU's component sequence appear as a contiguous run within the DN's? $max = $dnParts.Count - $ouParts.Count for ($i = 0; $i -le $max; $i++) { $hit = $true for ($j = 0; $j -lt $ouParts.Count; $j++) { if ($dnParts[$i + $j] -ne $ouParts[$j]) { $hit = $false; break } } if ($hit) { return $true } } } return $false } |