WMI win32_groupuser PowerShell 中的性能下降
WMI win32_groupuser slow performance in PowerShell
不确定这是不是我。我编写了一个脚本来检查远程服务器上本地管理员中是否存在域组。由于我公司有 20 多个域——其中许多域彼此隔离——我不确定这是否适用于使用 AD cmdlet。相反,我想我应该直接查询每台服务器的 WMI,这是一种通常对我有用的解决方案。
在这种情况下不是。这是我的脚本的主要部分:
$admin = Get-WmiObject win32_groupuser –computername $server | Where-Object $_.PartComponent -match $domaingroup} | Measure-Object
如果该组存在,则 $admin 的计数为正数,我可以就此进行报告。否则计数为 0,这也没关系。
但是今天,我被要求检查 200 台服务器上是否存在该组,但我的脚本失败了。这是狗慢。从每台服务器获取结果需要五到十 分钟。我可以更快地登录到服务器并直观地检查组。
这是 WMI 组之一吗,我不知道,每次触摸它时都会重建整个数据库,还是奇怪的东西?对更快的脚本有什么建议吗?
另一种方法是使用 ADSI 查询,例如:
$Results = ForEach($Server in (Get-Content .\ServerList.txt)){
$group = [ADSI]"WinNT://$Server/Administrators"
[PSCustomObject]@{'Server'=$Server
'Group Found' = [boolean](@($group.Invoke("Members")) |
foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}|
Where{ $_ -match $domaingroup}| Measure-Object)
}
}
如果在本地管理员组中找到 AD 组,那应该会留下一组服务器名称和 True/False。
这样试试:
$computerName = "."
$wmiEnumOpts = new-object System.Management.EnumerationOptions
$wmiEnumOpts.BlockSize = 20
$argList = @{
"Class" = "Win32_Group"
"ComputerName" = $computerName
"Filter" = "LocalAccount=TRUE AND SID='S-1-5-32-544'"
}
get-wmiobject @argList | foreach-object {
$_.GetRelated("Win32_Account","Win32_GroupUser","","",
"PartComponent","GroupComponent",$FALSE,$wmiEnumOpts)
}
更多细节在博客中post我刚才写过:
我终于走了一条不同的路:
$group = [ADSI]"WinNT://$Server/$LocalGroupName"
$members = @($group.Invoke("Members"))
foreach ($member in $members) {
$MemberName = $member.GetType().Invokemember("Name","GetProperty",$null,$member,$null)
if ($MemberName -eq $DomainGroupName) {
$GroupFound++ }}
因此,如果 $GroupFound 最终大于 0,则报告查找成功。否则,将其重置为 0 并在我列表中的下一台服务器上重新开始。每台服务器会在不到 10 秒左右的时间内报告,大约有 25:1 改进。
非常接近 TheMadTechnician 的解决方案,非常感谢。
不确定这是不是我。我编写了一个脚本来检查远程服务器上本地管理员中是否存在域组。由于我公司有 20 多个域——其中许多域彼此隔离——我不确定这是否适用于使用 AD cmdlet。相反,我想我应该直接查询每台服务器的 WMI,这是一种通常对我有用的解决方案。
在这种情况下不是。这是我的脚本的主要部分:
$admin = Get-WmiObject win32_groupuser –computername $server | Where-Object $_.PartComponent -match $domaingroup} | Measure-Object
如果该组存在,则 $admin 的计数为正数,我可以就此进行报告。否则计数为 0,这也没关系。
但是今天,我被要求检查 200 台服务器上是否存在该组,但我的脚本失败了。这是狗慢。从每台服务器获取结果需要五到十 分钟。我可以更快地登录到服务器并直观地检查组。
这是 WMI 组之一吗,我不知道,每次触摸它时都会重建整个数据库,还是奇怪的东西?对更快的脚本有什么建议吗?
另一种方法是使用 ADSI 查询,例如:
$Results = ForEach($Server in (Get-Content .\ServerList.txt)){
$group = [ADSI]"WinNT://$Server/Administrators"
[PSCustomObject]@{'Server'=$Server
'Group Found' = [boolean](@($group.Invoke("Members")) |
foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}|
Where{ $_ -match $domaingroup}| Measure-Object)
}
}
如果在本地管理员组中找到 AD 组,那应该会留下一组服务器名称和 True/False。
这样试试:
$computerName = "."
$wmiEnumOpts = new-object System.Management.EnumerationOptions
$wmiEnumOpts.BlockSize = 20
$argList = @{
"Class" = "Win32_Group"
"ComputerName" = $computerName
"Filter" = "LocalAccount=TRUE AND SID='S-1-5-32-544'"
}
get-wmiobject @argList | foreach-object {
$_.GetRelated("Win32_Account","Win32_GroupUser","","",
"PartComponent","GroupComponent",$FALSE,$wmiEnumOpts)
}
更多细节在博客中post我刚才写过:
我终于走了一条不同的路:
$group = [ADSI]"WinNT://$Server/$LocalGroupName"
$members = @($group.Invoke("Members"))
foreach ($member in $members) {
$MemberName = $member.GetType().Invokemember("Name","GetProperty",$null,$member,$null)
if ($MemberName -eq $DomainGroupName) {
$GroupFound++ }}
因此,如果 $GroupFound 最终大于 0,则报告查找成功。否则,将其重置为 0 并在我列表中的下一台服务器上重新开始。每台服务器会在不到 10 秒左右的时间内报告,大约有 25:1 改进。
非常接近 TheMadTechnician 的解决方案,非常感谢。