延迟运行Get-ADGroupMember

时间:2014-01-06 20:06:51

标签: powershell powershell-v3.0

是否有人能够告诉我为什么以下代码块运行速度如此之慢?当我为具有少数成员的组运行它时,它运行正常,但是当我为一个拥有640个成员的组运行时,有时它会成功运行,有时它会超时。域控制器是“本地的”(即不是通过WAN链路)。我从多台机器上尝试过这种方法并得到一些一致的(不合需要的)结果。 Get-ADGroupMember应该为具有<的组快速返回结果1000名会员?我认为它会,但我在这个问题上摸不着头脑。

Import-Module ActiveDirectory
$sw = [Diagnostics.Stopwatch]::StartNew()
Get-ADGroupMember -Identity cri-all_users | measure
$sw.Stop()
$sw.Elapsed

以下是我的输出示例:

Count    : 641
Average  : 
Sum      : 
Maximum  : 
Minimum  : 
Property : 

Ticks             : 2268358861
Days              : 0
Hours             : 0
Milliseconds      : 835
Minutes           : 3
Seconds           : 46
TotalDays         : 0.00262541534837963
TotalHours        : 0.0630099683611111
TotalMilliseconds : 226835.8861
TotalMinutes      : 3.78059810166667
TotalSeconds      : 226.8358861

这是我的$ PSVERSIONTABLE

PS C:\Windows\System32\WindowsPowerShell\v1.0> echo $PSVERSIONTABLE

Name                           Value
----                           -----
PSVersion                      3.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.18051
BuildVersion                   6.2.9200.16628
PSCompatibleVersions           {1.0, 2.0, 3.0}
PSRemotingProtocolVersion      2.2

我很感激任何人都能提供的任何见解。我已经开始尝试使用Process Explorer / Process Monitor在系统调用级别调试它并且(未成功)连接调试器,但是还没有走得太远。非常感谢你的帮助和时间。

2 个答案:

答案 0 :(得分:2)

当运行640个成员需要3分钟时,问题可能不在于域控制器或cmdlet本身。根据您的测量结果,我们以每秒约2.8个用户的速度运行,即使是最慢的DC也可以处理。您可以通过在中等大小的组上运行来证明这不是问题,如果您击败2.8个用户/秒,那么问题不在于DC。如果你的CPU没有固定在100%......你也可以证明它。

由于您可以查看的几个原因,我已经看到这个问题突然出现了:

  • 当组正在迭代时,它会尝试将SID解析为不存在的Active Directory对象。我会检查您的Active Directory,以确保没有丢失或损坏的AD用户/组。
  • 这也可能是因为外部安全校长无法解决
  • 虽然这可能不是特定情况,但是当您使用-Recurse参数调用Get-ADGroupMember时,可能需要花费相当多的时间来递归所有组。

当您通过大型组(如域用户)进行迭代时,通常会发生这些问题,因为它们更可能导致可能导致问题的SID损坏。每个损坏的SID都会导致Get-ADGroupMember cmdlet在尝试解析SID时暂停,在超时之前等待10-30秒,然后继续。

修复是找到那些不好的SID。解决方法是获取信息的不同方法,例如使用目录搜索器:

$searchRoot = New-Object System.DirectoryServices.DirectoryEntry
$adSearcher = New-Object System.DirectoryServices.DirectorySearcher
$adSearcher.SearchRoot = $searchRoot

$adSearcher.Filter = "(cn=groupName)"

$adSearcher.PropertiesToLoad.Add("member")
$samResult = $adSearcher.FindOne()

if($samResult)
 {
     $adAccount = $samResult.GetDirectoryEntry()
     $groupMembership = $adAccount.Properties["member"]
     $groupMembership | foreach { Write-Host $_ }
 }

答案 1 :(得分:1)

我只使用标准的命令行开关,在函数中打包以使其递归。比get-adgroupmember快得多,但不适用于"域用户"或其他主要群体成员。

function getmember($dn){
    $obj=get-adobject $dn
    if ($obj.objectclass -eq "group"){
        $grp=$obj|get-adgroup -property member
        $grp.member| foreach{ getmember $_ }
    }else{
        $dn
    }
}


$dn=(get-adgroup "Participants").distinguishedname

measure-command {
    $m= getmember $dn
}

measure-command {
    get-adgroupmember $dn -recursive|foreach{$_.distinguishedname}
}