传递directorydarcher

时间:2016-03-20 18:30:20

标签: powershell active-directory powershell-v3.0

目前,我知道您可以使用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个字符串值的方法?

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
    }
}