You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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."
}

关键修复点说明

  1. 传递嵌套遍历开关:递归调用时添加-IncludeNestedGroups:$IncludeNestedGroups,确保所有层级的组都遵循相同的遍历规则。
  2. 修正层级计数:直接使用$Level + 1作为递归的层级参数,移除易出错的$LevelCounter变量,保证每个嵌套组的层级计算准确。
  3. 明确对象类型判断:将else改为elseif ($MemberDetails.ObjectClass -eq "Group" -and $IncludeNestedGroups),避免误处理计算机、联系人等非组对象。
  4. 统一计数递增:将$valMember++移到try块的末尾(包括catch块),确保进度条的成员计数始终准确。

内容的提问来源于stack exchange,提问作者TheStingPilot

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:54:52