Поиск и глобальный каталог

Задача: имеется список guid-ов объектов в AD, для которых необходимо получить некоторый набор свойств. Объекты могут быть как пользователями, так и группами или контактами. Искать нужно внутри многодоменного леса, объекты могут быть внутри любого домена в лесе. Найти объект, вне зависимости от его типа, можно через командлет Get-ADObject:

Get-ADObject $guid

Небольшое затруднение возникает, если необходимо делать поиск по всем доменам одного леса. Очевидное решение в лоб – взять список доменов и в каждом из них провести поиск:

$Domains = (Get-ADForest).Domains

ForEach ($Domain in $Domains)
{
$Search = Get-ADObject $guid -Server (Get-ADDomain $Domain).PDCEmulator -ErrorAction Stop
}

Работать будет, но с ошибками. Очевидно, что по-конкретному guid-у объект будет возвращаться только из одного домена. Поиск в остальных доменах вернёт ошибку, так как такого объекта там не будет. Поэтому имеет смысл внести в скрипт try-catch:

$Domains = (Get-ADForest).Domains
$Results = @()
ForEach ($Domain in $Domains)
{
  try
  {
    $Search = Get-ADObject $guid -Server (Get-ADDomain $Domain).PDCEmulator -ErrorAction Stop
    $Found = $true
  }
  catch
  {
    $Found = $false
  }
  If ($Found)
  {
    $Results += New-Object PSObject -Property @{
    guid = $guid
    Domain = $Domain
    DistinguishedName = $Search.DistinguishedName
    ObjectClass = $Search.ObjectClass
    Found = $Found
    }
  }
}

Добавляем загрузку из txt-файла списка guid-ов:

$guids = Import-Csv -Path C:\guids.txt
$Domains = (Get-ADForest).Domains
$Results = @()
ForEach ($guid in $guids)
{
  ForEach ($Domain in $Domains)
  {
    try
    {
      $Search = Get-ADObject $guid -Server (Get-ADDomain $Domain).PDCEmulator -ErrorAction Stop
      $Found = $true
    }
    catch
    {
      $Found = $false
    }
    If ($Found)
    {
      $Results += New-Object PSObject -Property @{
      guid = $guid
      Domain = $Domain
      DistinguishedName = $Search.DistinguishedName
      ObjectClass = $Search.ObjectClass
      Found = $Found
      }
    }
  }
}
$Results | Where { $_.Found } | Select guid,Domain,DistinguishedName,ObjectClass,Found

Задача решена и можно запускать скрипт и ждать. Если доменов у нас с десяток, объектов для поиска больше сотни, то ждать придётся долго. Что с эти делать? Искать в глобальном каталоге! Правда, стоит помнить, что он содержит не все аттрибуты объектов. Для поиска в глобальном каталоге используем тот же Get-ADObject, но в ключе -Server нужно будет указать любой ближайший глобальный каталог, по-умолчанию доступный при обращении к порту 3268:

$LocalSite = (Get-ADDomainController -Discover).Site
$NewTargetGC = Get-ADDomainController -Discover -Service GlobalCatalog -SiteName $LocalSite
if (!$NewTargetGC)
{ $NewTargetGC = Get-ADDomainController -Discover -Service GlobalCatalog -NextClosestSite }
$NewTargetGCHostName = $NewTargetGC.HostName
$LocalGC = "$NewTargetGCHostName" + ":3268"

Try-catch при таком поиске нам будет нужен разве что для обработки поиска несуществующих guid-ов. Скрипт немного упростится:

$guids = Import-Csv -Path C:\guids.txt
$Results = @()
$LocalSite = (Get-ADDomainController -Discover).Site
$NewTargetGC = Get-ADDomainController -Discover -Service GlobalCatalog -SiteName $LocalSite
if (!$NewTargetGC)
{ $NewTargetGC = Get-ADDomainController -Discover -Service GlobalCatalog -NextClosestSite }
$NewTargetGCHostName = $NewTargetGC.HostName
$LocalGC = "$NewTargetGCHostName" + ":3268"
ForEach ($guid in $guids) 
{
  Try 
  {
    $Search = Get-ADObject -Identity $guid.guid -Server $LocalGC
  }
  Catch {
  }
  $Results += New-Object PSObject -Property @{
  guid = $guid.guid
  DistinguishedName = $Search.DistinguishedName
  ObjectClass = $Search.ObjectClass
  }
}
$Results | Select guid,DistinguishedName,ObjectClass

Скрипт при этом отрабатывать будет на пару порядков быстрее.

Полезные ссылки:
Powershell Code: Discover a Local Global Catalog for Forest Queries
PowerShell Code: Find User in Active Directory Forest
Get-ADDomainController
Get-ADObject

Leave a Reply

Your email address will not be published. Required fields are marked *