Powershell在Active Directory中查询用户

时间:2018-08-20 17:52:27

标签: powershell csv active-directory

我很难找到一种更有效的方式来从AD查询信息。就目前而言,我从我们的学生信息系统中导入了.csv个活跃用户文件。然后,我想从AD创建一个新的.csv文件,以用于活跃用户信息。这样,我正在查询每个用户(大约一万名学生)的AD。我有种感觉,我可以通过一个查询以某种方式完成此任务,但是没有运气。学生匹配存储在AD标题字段中的数字ID。该代码可以工作,但是要花几个小时才能运行。这是我用的:

$Users = Import-Csv "c:\DASLExport.csv" -Header @("a") | Select a
$usersarray = @()
ForEach ($Row in $Users) {
    $userSearchString = $Row.a
    $currentUser = (Get-ADUser -Filter {Title -eq $userSearchString} -Properties title, SamAccountName, extensionAttribute1)
    $UserObj = New-Object PSObject
    Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "ID" -Value $($currentUser.title)
    Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "Username" -Value $($currentUser.SamAccountName) 
    Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "Password" -Value $($currentUser.extensionAttribute1)
    $usersarray += $UserObj
}

If($usersarray.count -gt 0) {$usersarray | Export-Csv -Path 'c:\users.csv' -NoTypeInformation}

2 个答案:

答案 0 :(得分:3)

我认为,与其用Get-ADUser查询每个用户,不如一次获取所有具有标题的用户并将其保存到变量中,然后查询该变量。

此外,常规数组的大小是固定的,这意味着每次插入新元素时,您实际上都会创建新数组并将所有数据复制到其中,然后一次又一次地重复它,这会花费很多时间。所以切换到打算增长的ArrayList,它将更快。

亲自检查:

$ArrayList = New-Object System.Collections.ArrayList
$RegularArray = @()

Measure-Command { 1..10000 | % {[void]$ArrayList.Add($_)} }
Measure-Command { 1..10000 | % {$RegularArray += $_ } }

例如,请尝试以下操作:

$Users = Import-Csv "c:\DASLExport.csv" -Header @("a") | Select a
$ADUsers = Get-ADUser -Filter {Title -ne "$null"} -Properties title, SamAccountName, extensionAttribute1
$Usersarray = New-Object System.Collections.ArrayList

ForEach ($Row in $Users) {
    $userSearchString = $Row.a
    $currentUser = $ADUsers | ? {$_.Title -eq $userSearchString}
    if (!$currentUser) {continue}
    $UserObj = New-Object PSObject
    Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "ID" -Value $($currentUser.title)
    Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "Username" -Value $($currentUser.SamAccountName) 
    Add-Member -InputObject $UserObj -MemberType NoteProperty -Name "Password" -Value $($currentUser.extensionAttribute1)
    [void]$usersarray.Add($UserObj)
}

If($usersarray.count -gt 0) {$usersarray | Export-Csv -Path 'c:\users.csv' -NoTypeInformation}

答案 1 :(得分:1)

@Avshalom的答案很有用,但可以改进:

[CmdletBinding()]
param
(
    [Parameter(Position = 0)]
    [ValidateScript({Test-Path -Path $PSItem -PathType Leaf})]
    [string]
    $Path = 'C:\DASLExport.csv',

    [Parameter(Position = 1)]
    [ValidateScript({Test-Path -Path $PSItem -PathType Leaf -IsValid})]
    [string]
    $Destination = 'C:\users.csv'
)

$csv = Import-Csv -Path $Path -Header a
$users = @(Get-ADUser -Filter 'Title -ne "$null"' -Properties Title, SamAccountName, extensionAttribute1)

$collection = foreach ($row in $csv)
{
    $title = $row.a
    $user = $users.Where{$PSItem.Title -eq $title}
    if (-not $user)
    {
        Write-Warning -Message "User $title not found."
        continue
    }

    [pscustomobject]@{
        ID       = $user.Title
        Username = $user.SamAccountName
        Password = $user.extensionAttribute1
    }
}

$collection | Export-Csv -Path $Destination -NoTypeInformation

您可以将foreach循环的输出直接分配给变量,而无需管理列表对象(尽管如果您选择列表,则应使用System.Collections.Generic.List<Type>,因为{{ 1}}已弃用)。另外,您不需要使用ArrayList语句,因为您的Select-Object已被加载,并且在这种情况下它仅处理两次。速度上最大的改进不是查询数以千计的AD,而是将其保存在单个对象中,而是主要通过不使用csv / [array]


速度比较:

@()

$L = 1..100000

〜70ms

Measure-Command {$col = foreach ($i in $L) { $i }}

〜110ms

Measure-Command {$col = [System.Collections.Generic.List[int]]::new(); foreach ($i in $L) { $col.Add($i) }}

〜46秒