PowerShell嵌套AD组成员查询脚本无法遍历深层组问题排查
问题分析与修复方案
核心问题
脚本无法遍历三层及更深嵌套组的根本原因是递归调用时未传递-IncludeNestedGroups开关参数:
第一次调用函数时你传入了-IncludeNestedGroups,但递归处理第二层组(如Demo - DummyGroup2)时,没有传递该参数,导致函数默认使用$IncludeNestedGroups = $false,不会继续遍历下层嵌套组(如Demo - DummyGroup3)。
此外还有两个次要问题:
$LevelCounter变量在函数作用域内被循环修改,若同一组内有多个嵌套组,会导致层级计数错误。$valMember仅在处理用户时递增,进度条的成员计数会出现偏差。
修复后的完整脚本
Function Get-NestedGroupsAndMembers { Param ( [String] $DomainName, [String] $ADGroupName, [Int] $Level = 0, [Switch] $IncludeNestedGroups ) $arrTable = @() $valMember = 1 Try { $ServerHostname = $(Get-ADDomainController -DomainName $DomainName -Discover).HostName[0] $Members = (Get-ADGroup -Identity $ADGroupName -Server $ServerHostname -Properties Members).Members $MemberCount = $Members.Count } Catch { $Record = [ordered] @{ "Domain" = $DomainName "Group" = $ADGroupName "Consolidated Groupname"= "$DomainName\$ADGroupName" "SAMAccountName" = "" "Mail" = "" "DisplayName" = "" "objectClass" = "" "Level" = "" "Error" = "Error on '$DomainName\$ADGroupName' with server '$ServerHostname': $($_.Exception.Message)" } $arrTable += New-Object PSObject -Property $Record Return $arrTable } Write-Progress -Id ($Level+1) -Activity "Processing groups" -Status "Processing $DomainName\$ADGroupname" ForEach ($Member in $Members) { Try { Write-Progress -Activity "Processing members of $DomainName\$ADGroupName" ` -Status "Processing member $valMember of $MemberCount" ` -Id ($Level+2) -ParentId ($Level+1) ` -PercentComplete ($valMember / $MemberCount * 100) $MemberDetails = Get-ADObject -Server $ServerHostname ` -Filter {DistinguishedName -eq $Member} ` -Properties SAMAccountName, Mail, displayName, objectclass if ($MemberDetails.ObjectClass -eq "User") { $Record = [ordered] @{ "Domain" = $DomainName "Group" = $ADGroupName "Consolidated Groupname"= "$DomainName\$ADGroupName" "SAMAccountName" = $MemberDetails.SAMAccountName "Mail" = $MemberDetails.Mail "DisplayName" = $MemberDetails.DisplayName "objectClass" = $MemberDetails.objectClass "Level" = $Level "Error" = "" } $arrTable += New-Object PSObject -Property $Record } elseif ($MemberDetails.ObjectClass -eq "Group" -and $IncludeNestedGroups) { # 递归调用时传递IncludeNestedGroups参数,使用Level+1作为新层级 $arrTable += Get-NestedGroupsAndMembers -DomainName $DomainName ` -ADGroupName $MemberDetails.SAMAccountName ` -Level ($Level + 1) ` -IncludeNestedGroups:$IncludeNestedGroups } $valMember++ # 无论成员类型,都递增计数,保证进度条准确 } Catch { $Record = [ordered] @{ "Domain" = $DomainName "Group" = $ADGroupName "Consolidated Groupname"= "$DomainName\$ADGroupName" "SAMAccountName" = "" "Mail" = "" "DisplayName" = "" "objectClass" = "" "Level" = "" "Error" = "Error on '$DomainName\$ADGroupName' with server '$ServerHostname': $($_.Exception.Message)" } $arrTable += New-Object PSObject -Property $Record Write-Host "Error on '$DomainName\$ADGroupName' with server '$ServerHostname': $($_.Exception.Message)" $valMember++ } } Write-Progress -Id ($Level+2) -ParentId ($Level+1) -Completed -Activity "Completed" Return $arrTable } Clear-Host $CurrentPath = Split-Path -parent $MyInvocation.MyCommand.Definition $GroupName = "Demo - DummyGroup1" $FileName = Join-Path $CurrentPath "$GroupName.csv" $Results = Get-NestedGroupsAndMembers -DomainName (Get-ADDomain).DNSRoot ` -ADGroupName $GroupName ` -IncludeNestedGroups | Sort-Object -Property Level If ($Results) { $DelimiterChar = ";" $Results | Export-CSV $FileName -NoTypeInformation -Delimiter $DelimiterChar -Encoding UTF8 Write-Host "$FileName has been created." }
关键修复点说明
- 传递嵌套遍历开关:递归调用时添加
-IncludeNestedGroups:$IncludeNestedGroups,确保所有层级的组都遵循相同的遍历规则。 - 修正层级计数:直接使用
$Level + 1作为递归的层级参数,移除易出错的$LevelCounter变量,保证每个嵌套组的层级计算准确。 - 明确对象类型判断:将
else改为elseif ($MemberDetails.ObjectClass -eq "Group" -and $IncludeNestedGroups),避免误处理计算机、联系人等非组对象。 - 统一计数递增:将
$valMember++移到try块的末尾(包括catch块),确保进度条的成员计数始终准确。
内容的提问来源于stack exchange,提问作者TheStingPilot
相关产品推荐
相关产品推荐

