递归PowerShell函数无法自调用:AD OU结构遍历失败排查
问题排查与修正方案
原代码核心问题分析
- DN数组操作逻辑错误:
原代码中$ChildOUs | ForEach-Object{$_.DN.Remove($_.Name)}会移除当前OU名称,导致子OU的DN列表残留父OU名称,触发if($cOU.DN){ Continue }被跳过,直接忽略子OU的处理。 - 递归参数传递错误:
调用递归函数时未将当前OU名称作为新的父OU传递,而是沿用初始的$ParentOU,导致缩进和子OU筛选完全失效。 - 缩进逻辑不足:
仅用固定空格区分有无父OU,无法适配多层嵌套的缩进需求。 - 子OU筛选不准确:
使用$_.DN -contains $Parent无法精准匹配直接父OU,因为DN数组是叶子到根的顺序,容易误匹配非直接父级的OU。
修正后的完整代码
function Display-OU { param( [String]$ParentOU, [PSObject[]]$AllOUs, [int]$Depth = 0 ) # 根据递归深度计算缩进,每深一层增加2个空格 $spacing = " " * $Depth # 筛选当前父OU下的直接子OU $childOUs = if ($ParentOU) { $AllOUs | Where-Object { $_.ParentOU -eq $ParentOU } } else { # 顶级OU:直接隶属于域的OU(无父OU) $AllOUs | Where-Object { -not $_.ParentOU } } foreach ($ou in $childOUs) { # 输出当前OU(带对应缩进) "$spacing$($ou.Name)" # 递归处理当前OU的子OU,深度+1 Display-OU -ParentOU $ou.Name -AllOUs $AllOUs -Depth ($Depth + 1) } } # 获取所有OU并预处理父OU信息 $rawOUs = Get-ADOrganizationalUnit -Filter * | Select-Object Name, DistinguishedName $processedOUs = foreach ($ou in $rawOUs) { # 拆分DistinguishedName,提取所有OU层级(去掉DC部分) $ouHierarchy = ($ou.DistinguishedName -split ',') | Where-Object { $_ -match '^OU=' } | ForEach-Object { $_ -replace '^OU=' } # 直接父OU是层级中的第二个元素(DistinguishedName格式为 OU=子,OU=父,...) $parentOU = if ($ouHierarchy.Count -gt 1) { $ouHierarchy[1] } else { $null } [PSCustomObject]@{ Name = $ou.Name ParentOU = $parentOU Domain = ($ou.DistinguishedName -split ',') | Where-Object { $_ -match '^DC=' } | ForEach-Object { $_ -replace '^DC=' } -join '.' } } # 按域分组输出OU结构 $processedOUs | Group-Object Domain | ForEach-Object { Write-Host "[$($_.Name)]" Display-OU -AllOUs $_.Group }
修正说明
- 递归函数重构:
- 新增
$Depth参数控制缩进深度,支持任意多层嵌套的缩进格式。 - 使用
$AllOUs传递全量OU数据,避免修改原数据导致的筛选错误。 - 通过
ParentOU属性精准筛选直接子OU,逻辑清晰且不易出错。
- 新增
- OU数据预处理:
- 直接从DistinguishedName中提取每个OU的直接父OU名称,简化层级判断逻辑。
- 正确拆分并拼接域名称,确保跨域场景下的分组输出正确。
- 递归逻辑修复:
递归调用时传递当前OU名称作为新的ParentOU,同时将深度+1,保证缩进和子OU筛选的连贯性。
预期输出效果
针对示例OU结构,运行后会输出:
[Domain.local] Domain Controllers Users Internal External
内容的提问来源于stack exchange,提问作者Al D. J.
相关产品推荐
相关产品推荐

