目前,我知道您可以使用ldap过滤器获取帐户,例如$adSearchFilter = "(&(objectCategory=User)(samAccountType:1.2.840.113556.1.4.803:=805306368)(SamAccountName='Account1'))
。有没有办法让ldap过滤器允许你通过名单列表,比如使用=
我可以使用像-contains
这样的东西?
下面是代码,正如您所看到的,它一次搜索一个用户进行foreach循环中的整个搜索过程......
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个字符串值的方法?
答案 0 :(得分:1)
LDAP没有类似-contains
的语句,但您可以使用OR运算符(|
)构造一个匹配多个精确值的过滤器表达式:
(|(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 MB为了安全起见):
$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
}
}