我很难找到一种更有效的方式来从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}
答案 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秒