Ошибка перехвата из-за тайм-аута сервера Get-ADObject - PullRequest
0 голосов
/ 09 декабря 2018

Когда я запускаю этот скрипт из Тим Раймер , я получаю сообщения об ошибках от некоторых из моих контроллеров домена, когда сервер по какой-то причине отключается.Когда я получаю сообщение об ошибке ниже, скрипт останавливается на 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

1 Ответ

0 голосов
/ 09 декабря 2018

Как видно из ошибки, вы получаете 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 = ...
        ...
    }
    
  • используйте фоновые задания для параллельного выполнения операций

    $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 (Get-ADUser $user.SamAccountName), , а затем выполняет фактический запрос к конкретному DC (Get-ADObject).

Вы должны быть в состоянии значительно ускорить код, выполнив всего один запрос для всех пользователей к каждому DC.Сгруппируйте результаты по SamAccountName и выберите запись с самой последней отметкой времени из каждой группы, затем экспортируйте результаты в CSV.

$fltr  = '(&(objectClass=user)(objectCategory=person))'
$props = 'SamAccountName', 'LastLogon'

Get-ADDomainController -Filter * |
    Select-Object -Expand HostName |
    Where-Object { Test-Connection -Computer $_ -Count 2 -Quiet } |
    ForEach-Object { Get-ADObject -LDAPFilter $fltr -Properties $props -Server $_ } |
    Select-Object Name, SamAccountName,
        @{n='LastLogon';e={[DateTime]::FromFileTime($_.LastLogon)}} |
    Group-Object SamAccountName |
    ForEach-Object { $_.Group | Sort-Object LastLogon | Select-Object -Last 1 } |
    Export-Csv $exportFilePath -NoType
...