问题描述
我目前正在尝试查询域控制器以查找用户的最新登录日期。我知道我可以使用 lastlogondate 但这不会像我想要的那样经常复制,而且我无法控制它。我尝试制作一个脚本来查询每个域控制器并根据用户哈希表检查它,但事实证明,即使查询一个 DC 也非常慢。我知道我可以为每个 DC 运行后台作业,但仍然只是访问一个域控制器的所有最新登录时间需要很长时间。有什么建议吗?
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$users = Get-ADUser -filter * -SearchBase "OU=users,DC=com"
$outfile = "c:users.csv"
$usertable = @{}
# creating table for all users
foreach($user in $users) {
$userobject = New-Object PSObject
$userobject | Add-Member -MemberType NoteProperty -Name DomainController -Value "0"
$userobject | Add-Member -MemberType NoteProperty -Name Lastlogon -Value "0"
$usertable.Add($user.SamAccountName,$userObject)
} # end foreach
# Method for looping through domain controllers to find last logon
foreach($dc in $dcs) {
$hostname = $dc.HostName
$logons = Get-ADUser -Filter * -SearchBase "OU=users,DC=com" -Property Lastlogon -Server $hostname
foreach($u in $logons) {
$sam = $u.SamAccountName
if($u.Lastlogon -gt $usertable.$sam.Lastlogon) {
$usertable.$sam.Lastlogon = $u.Lastlogon
$usertable.$sam.DomainController = $dc.HostName
Write-Host "$sam has the latest date"
$usertable.$sam.DomainController
}
} #end inner foreach
} #end outer domain foreach
foreach($h in $usertable.GetEnumerator()) {
$sam = $($h.Name)
$newdate = $($h.Value).Lastlogon
$append = "$sam,$newdate"
$append | out-file $outfile -Encoding ascii -Force -Append
}
解决方法
我想我已经弄清楚了。通过测试和我自己的类似程序对比很明显,延迟在以下循环中:
foreach($u in $logons) {
$sam = $u.SamAccountName
if($u.LastLogon -gt $usertable.$sam.LastLogon) {
$usertable.$sam.LastLogon = $u.LastLogon
$usertable.$sam.DomainController = $dc.HostName
Write-Host "$sam has the latest date"
$usertable.$sam.DomainController
}
} # end inner foreach
现在我的程序和你的不完全一样。可以对此进行消毒,但出于所有意图和目的,以下部分与上述摘录具有相同的功能:
# Note: the re-use of $DC...
ForEach($DC in $RDCs )
{ # Should you add any measurements here??
Write-Host "Working on $DC : $(Get-Date -Format G) ..."
Get-ADUser -Filter $Filter -SearchBase $SearchBase -Server $DC -Properties $AD_Props |
ForEach-Object{
If ( $Users.Contains( $_.samAccountName ) )
{ # So you don't attemp when it wasn't in the root set.
If( $_.lastlogon -gt $Users[$_.samAccountName].LastLogon )
{
$Users[$_.samAccountName].LastLogon = $_.lastlogon
$Users[$_.samAccountName].DC = $DC
}
}
}
}
您可以看到我使用的是 ForEach-Object
循环而不是 ForEach
构造。然而,这并不是一个充分的解释,尤其是后者通常更快。
注意:我以几种不同的方式为您的循环计时,并在脚本的前面说明了代码。例如,我没有以同样的方式创建对象,但我排除了这一因素。
无法弄清楚为什么您的循环会“显着”变慢,我不情愿地将其重写为:
$logons |
ForEach-Object{
If( $_.LastLogon -gt $usertable[$_.samAccountName].LastLogon )
{
$usertable[$_.samAccountName].LastLogon = $_.LastLogon
$usertable[$_.samAccountName].DomainController = $hostname
然而,这似乎并没有快多少。所以,我更不情愿地尝试了:
Get-ADUser -Filter * -SearchBase $UsersOU -Property LastLogon -Server $hostname |
ForEach-Object{
If( $_.LastLogon -gt $usertable[$_.samAccountName].LastLogon )
{
$usertable[$_.samAccountName].LastLogon = $_.LastLogon
$usertable[$_.samAccountName].DomainController = $hostname
}
}
现在我开始看到与我自己的程序类似的性能。事实上,它看起来有点快,可能是因为没有检查哈希。
根据经验,我只能假设这些对象是活动的并且保持某种与源 DC 的连接。我之前在 PowerShell 社区扩展 (PSCX) 中见过这种类型的东西,从 Get-TerminalSession
返回的对象表现出类似的行为。我可能是疯了,我很高兴得到纠正,坦率地说,我希望有人有更好的解释。
我还可以在这里提出一些其他建议,但没有像上述那样有影响力。另请注意,我没有测试到底,所以不能保证没有其他问题。