从Tim Rhymer运行此脚本时,我从某些域控制器收到错误,这些服务器由于某种原因服务器超时。当我收到以下错误时,它将脚本停滞15-30秒,而不是查询域控制器花费1-2秒。我如何才能捕获该错误并且不会使脚本停滞这么长时间?以下是
部分错误消息:
Get-ADObject : Unable to contact the server. This may be because this server does not exist, it is currently down, or it does not have the Active Directory Web Services running. At C:\Users\jimbob\AD_Lookup.ps1:58 char:54 + ... countName | Get-ADObject -Server $hostname -Properties lastlogon <# - ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceUnavailable: (CN=jimbob...DC=domaincontroller,DC=com:User) [Get-ADObject], ADServerDownException + FullyQualifiedErrorId : ActiveDirectoryServer:0,Microsoft.ActiveDirectory.Management.Commands.GetADObject
下面是查询域控制器以从所有域控制器获取上次登录日期的脚本。
Import-Module ActiveDirectory
function Get-ADUsersLastLogon() {
$dcs = Get-ADDomainController -Filter {Name -like "*"}
$users = Get-ADUser -Filter *
$time = 0
$exportFilePath = "c:lastLogon.csv"
$columns = "name,username,datetime"
Out-File -FilePath $exportFilePath -Force -InputObject $columns
foreach ($user in $users) {
foreach ($dc in $dcs) {
$hostname = $dc.HostName
$currentUser = Get-ADUser $user.SamAccountName | Get-ADObject -Server $hostname -Properties lastLogon
if ($currentUser.LastLogon -gt $time) {
$time = $currentUser.LastLogon
}
}
$dt = [DateTime]::FromFileTime($time)
$row = $user.Name + "," + $user.SamAccountName + "," + $dt
Out-File -FilePath $exportFilePath -Append -NoClobber -InputObject $row
$time = 0
}
}
Get-ADUsersLastLogon
我认为我需要更改某些内容以捕获错误,或者从脚本的以下部分之一绕过导致错误的问题:
$dcs = Get-ADDomainController -Filter {Name -like "*"}
或
$currentUser = Get-ADUser $user.SamAccountName |
Get-ADObject -Server $hostname -Properties lastLogon
答案 0 :(得分:1)
从错误中您可以看到,您得到了ADServerDownException
。您可以像这样捕获并处理特定的异常:
try {
$currentUser = Get-ADUser $user.SamAccountName |
Get-ADObject -Server $hostname -Properties lastLogon
} catch [Microsoft.ActiveDirectory.Management.ADServerDownException] {
# handle AD server unreachable
} catch {
# handle all other exceptions
}
如果您希望所有其他异常仅冒泡给调用者而不是您自己处理,则末尾的catch
可以省略。
但是,这不会加快代码的速度,因为只会在发生超时后 引发异常。为了减少代码的执行时间,您可以
在尝试与服务器进行交互之前,例如,检查服务器是否可访问
if (Test-Connection -Computer $hostname -Count 2 -Quiet) {
$currentUser = ...
...
}
使用background jobs并行运行操作
$jobs = foreach ($dc in $dcs) {
Start-Job -ScriptBlock {
Param($username, $hostname)
Get-ADUser $username |
Get-ADObject -Server $hostname -Properties lastLogon
} -ArgumentList $user.SamAccountName, $dc.HostName
}
$jobs | Wait-Job | Receive-Job
$jobs | Remove-Job
但是,可以说,代码中最大的瓶颈是它首先从AD(Get-ADUser -Filter *
)获取所有用户,然后再次再次查询每个用户的DC({{1} }),然后然后对特定DC(Get-ADUser $user.SamAccountName
)运行实际查询。
通过针对每个DC对所有用户运行单个查询,您应该能够大大加快代码的速度。将结果按Get-ADObject
分组,并从每个组中选择带有最近时间戳记的记录,然后将结果导出到CSV。
SamAccountName