2016-03-20 1 views
0

Так что в настоящее время я знаю, что вы можете захватить учетную запись, используя фильтр ldap для чего-то вроде $adSearchFilter = "(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368)(SamAccountName='Account1')). Есть ли способ, которым фильтр ldap позволит вам пройти список имен, например, вместо использования = Я могу использовать что-то вроде -contains?передать список свойств в ldap-фильтре для directorysearcher

Ниже приведен код, и, как вы можете видеть, он ищет одного пользователя в то время, в течение всего процесса поиска в цикле Еогеасп ...

Function GetUsersInfoFromDomain 
{ 
    Param ([String]$searchPropertyName, [String[]]$searchPropertyValues, [String[]]$DcWithCred,[String]$domainShortName, [String[]]$userProperties) 

    $queryTable = @() 
    ForEach ($searchPropertyValue in $searchPropertyValues) 
    { 
     $adSearchFilter = "(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368)($searchPropertyName=$searchPropertyValue))" 
     Write-Host "Searching domain $domainShortName with $searchPropertyName $searchPropertyValue" 
     $searchDomainResultsTable = powershell -command { 
      Param ([String]$adSearchFilter, [String[]]$userProperties,[String[]]$DcWithCred, [String]$domainShortName) 
      [string]$DC = $DcWithCred[0] 
      [string]$Username = $DcWithCred[1] 
      [string]$Password = $DcWithCred[2] 
      [string]$domain = "LDAP://$DC" 

      $adDomain = New-Object System.DirectoryServices.DirectoryEntry($domain, $Username, $Password) 
      $adSearcher = New-Object System.DirectoryServices.DirectorySearcher($adDomain) 
      $adSearcher.Filter = $adSearchFilter 
      $adSearcher.PageSize=1000 
      $adSearcher.PropertiesToLoad.AddRange($userProperties) | out-Null 
      $userRecords = $adSearcher.FindAll() 
      $adSearcher.Dispose() | Out-Null 
      [System.GC]::Collect() | Out-Null 

      # The AD results are converted to an array of hashtables. 
      $userPropertiesTable = @() 
      foreach($record in $userRecords) { 
       $hashUserProperty = @{} 
       foreach($userProperty in $userProperties){ 
        if (($userProperty -eq 'objectGUID') -or ($userProperty -eq 'objectSid') -or ($userProperty -eq 'msExchMasterAccountSid')) { 
         if ($record.Properties[$userProperty]) { 
          $hashUserProperty.$userProperty = $record.Properties[$userProperty][0] 
         } else { 
         $hashUserProperty.$userProperty = $null 
         } 
        } Else { 
         if ($record.Properties[$userProperty]) { 
          $hashUserProperty.$userProperty = ($record.Properties[$userProperty] -join '; ').trim('; ') 
         } else { 
         $hashUserProperty.$userProperty = $null 
         } 
        } #end Else 
       } #end ForEach 
       $userPropertiesTable += New-Object PSObject -Property $hashUserProperty 
      } #end ForEach 
      [System.GC]::Collect() | Out-Null 

      # Fixes the property values to be a readable format before exporting to csv file 
      $listOfBadDateValues = '9223372036854775807', '9223372036854770000', '0' 
      $maxDateValue = '12/31/1600 5:00 PM' 
      $valuesToFix = @('lastLogonTimestamp', 'AccountExpires', 'LastLogon', 'pwdLastSet', 'objectGUID', 'objectSid', 'msExchMasterAccountSid') 
      $extraPropertyValues = @('Domain Name') 
      $valuesToFixCounter = 0 
      $extraPropertyValuesCounter = 0 
      $valuesToFixFound = @($false, $false, $false, $false, $false, $false, $false) 
      $extraPropertyValuesFound = @($false) 

      ForEach ($valueToFix in $valuesToFix) 
      { 
       if ($userProperties -contains $valueToFix) 
       { 
        $valuesToFixFound[$valuesToFixCounter] = $true 
       } 
       $valuesToFixCounter++ 
      } 

      ForEach ($extraPropertyValue in $extraPropertyValues) 
      { 
       if ($userProperties -contains $extraPropertyValue) 
       { 
        $extraPropertyValuesFound[$extraPropertyValuesCounter] = $true 
       } 
       $extraPropertyValuesCounter++ 
      } 

      $tableFixedValues = $userPropertiesTable | % { 
       if ($valuesToFixFound[0]) { 
        if ($_.lastLogonTimestamp) { 
         $_.lastLogonTimestamp = ([datetime]::FromFileTime($_.lastLogonTimestamp)).ToString('g') 
        } 
       }; if ($valuesToFixFound[1]) { 
        if (($_.AccountExpires) -and ($listOfBadDateValues -contains $_.AccountExpires)) { 
         $_.AccountExpires = "" 
        } else { 
         if (([datetime]::FromFileTime($_.AccountExpires)).ToString('g') -eq $maxDateValue) { 
          $_.AccountExpires = "" 
         } Else { 
          $_.AccountExpires = ([datetime]::FromFileTime($_.AccountExpires)).ToString('g') 
         } 
        } 
       }; if ($valuesToFixFound[2]) { 
        if (($_.LastLogon) -and ($listOfBadDateValues -contains $_.LastLogon)) { 
         $_.LastLogon = "" 
        } else { 
         if (([datetime]::FromFileTime($_.LastLogon)).ToString('g') -eq $maxDateValue) { 
          $_.LastLogon = "" 
         } Else { 
          $_.LastLogon = ([datetime]::FromFileTime($_.LastLogon)).ToString('g') 
         } 
        } 
       }; if ($valuesToFixFound[3]) { 
        if (($_.pwdLastSet) -and ($listOfBadDateValues -contains $_.pwdLastSet)) { 
         $_.pwdLastSet = "" 
        } else { 
         if (([datetime]::FromFileTime($_.pwdLastSet)).ToString('g') -eq $maxDateValue) { 
          $_.pwdLastSet = "" 
         } Else { 
          $_.pwdLastSet = ([datetime]::FromFileTime($_.pwdLastSet)).ToString('g') 
         } 
        } 
       }; if ($valuesToFixFound[4]) { 
        if ($_.objectGUID) { 
         $_.objectGUID = ([guid]$_.objectGUID).Guid 
        } Else { 
         $_.objectGUID = "" 
        } 
       }; if ($valuesToFixFound[5]) { 
        if ($_.objectSid) { 
         $_.objectSid = (New-Object Security.Principal.SecurityIdentifier($_.objectSid, 0)).Value 
        } Else { 
         $_.objectSid = "" 
        } 
       }; if ($valuesToFixFound[6]) { 
        if ($_.msExchMasterAccountSid) { 
         $_.msExchMasterAccountSid = (New-Object Security.Principal.SecurityIdentifier($_.msExchMasterAccountSid, 0)).Value 
        } Else { 
         $_.msExchMasterAccountSid = "" 
        } 
       }; If ($extraPropertyValuesFound[0]) { 
        If (!($_.'Domain Name')) { 
         $_.'Domain Name' = $domainShortName 
        } 
       };$_} 
       [System.GC]::Collect() | Out-Null 

       $sortedTableColumns = $tableFixedValues | Select-Object $userProperties 
       [System.GC]::Collect() | Out-Null 

       return $sortedTableColumns 
     } -args $adSearchFilter, $userProperties, $DcWithCred, $domainShortName 
     [System.GC]::Collect() | Out-Null 
     Write-Host "Search Complete." 
     Write-Host "" 

     if ($searchDomainResultsTable) 
     { 
      $queryTable += $searchDomainResultsTable 
     } 
    } # End ForEach Loop 
    Write-Host 'Exporting domain search results to table...' 
    Write-Output $queryTable 
} 

Я думал о делать что-то вроде $adSearchFilter += "($searchPropertyName=$searchPropertyValue)". Однако из-за предела 10mb - What is the LDAP filter string length limit in Active Directory?, я не уверен, был ли это лучший метод при поиске 200 000 пользователей ++.

Кто-нибудь знает способ передачи списка вместо 1 строкового значения для каждого поиска?

+1

Зачем вам фильтровать 200000+ конкретных пользователей в том же поиске? –

+0

из 1mil + в домене, я буду искать свойства, которые соответствуют в различных других приложениях и базах данных. –

ответ

1

LDAP не имеет -contains -как заявление, но вы можете использовать оператор (|) или построить выражение фильтра, который соответствует несколько точных значений:

(|(samaccountname=user1)(samaccountname=user2)(samaccountname=user3)) 

Это, как я бы построить фильтрующая строка:

$FilterTemplate = '(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368){0})' 
$ClauseTemplate = "($searchPropertyName={0})" 
$AllClauses  = $searchPropertyValues |ForEach-Object { $ClauseTemplate -f $_ } 
$adSearchFilter = $FilterTemplate -f $($AllClauses -join '') 

Это, как говорится, зачем вы передавали 200000 конкретных значений для поиска в одном поиске? LDAP поддерживает сопоставление подстановочных знаков (например, (samaccountname=*)).

В любом случае, вы можете рассчитать конечный размер вашей строки, путем вызова Encoding.GetByteCount на самой большой строки в $AllClauses, а затем использовать его для разбиения массива (давайте довершение на 9,5 Мб, чтобы быть на безопасной стороне) :

$LongestString = $AllClauses |Sort -Property Length |Select -Last 1 
$LongestByteCount = [System.Text.Encoding]::Unicode.GetByteCount($LongestString) 
if(($LongestByteCount * $AllClauses.Count) -gt 9.5MB) 
{ 
    $MaxCount = [int](9.5MB/$LongestByteCount) 
    for($i = 0; $i -lt $AllClauses.Count; $i += $MaxCount) 
    { 
     $ClauseSubset = $AllClauses[$i..$($i + $MaxCount - 1)] 
     $adSearchFilter = $FilterTemplate -f $($ClauseSubset -join '') 
     # Do your search 
    } 
} 
+0

Ответ на ваш вопрос был приведен в комментарии выше. Я написал небольшой скрипт, используя цикл for, чтобы создать строку '(sadfjweoqifhnweqhfweqofhqe = hnqfkohwqopfnh2fh2qf023f0)' 200 000 раз, а затем экспортировать ее в txt-файл. Файл имеет длину 10.5 мб. Так что, похоже, моя теория была правильной (в вопросе). Однако, возможно, я могу заставить его использовать это как условие (если он меньше 200 000 бросков в большой строке для поиска, а затем искать каждого пользователя 1 за раз). –

+0

@FiddleFreak Достаточно честный, обновленный ответ с примером того, как рассчитать размер строки и соответствующим образом распределить массив. –

+0

Спасибо, кучка :) –

Смежные вопросы