Powershell在Active Directory中查询用户
我很难找到一种更有效的方式从广告中查询信息。目前,我从我们的学生信息系统导入了一个活动用户的Powershell在Active Directory中查询用户,powershell,csv,active-directory,Powershell,Csv,Active Directory,我很难找到一种更有效的方式从广告中查询信息。目前,我从我们的学生信息系统导入了一个活动用户的.csv文件。然后,我想创建一个新的.csv文件,其中包含来自广告的活动用户信息。因此,我正在查询每个用户的广告(大约10000名学生)。我有一种感觉,我可以通过一次查询以某种方式完成此任务,但运气不佳。学生匹配存储在广告标题字段中的数字ID。代码确实可以运行,但是运行需要几个小时。以下是我使用的: $Users = Import-Csv "c:\DASLExport.csv" -Header @("a"
.csv
文件。然后,我想创建一个新的.csv
文件,其中包含来自广告的活动用户信息。因此,我正在查询每个用户的广告(大约10000名学生)。我有一种感觉,我可以通过一次查询以某种方式完成此任务,但运气不佳。学生匹配存储在广告标题字段中的数字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}
我认为,与其用
getaduser
查询每个用户,不如一次获取所有具有title的用户并将其保存到一个变量中,然后查询这个变量
此外,常规数组的大小是固定的,这意味着每次插入新元素时,实际上都会创建新数组并将所有数据复制到其中,然后一次又一次地重复,这需要很多时间。因此,切换到打算增长的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}
我认为,与其用
getaduser
查询每个用户,不如一次获取所有具有title的用户并将其保存到一个变量中,然后查询这个变量
此外,常规数组的大小是固定的,这意味着每次插入新元素时,实际上都会创建新数组并将所有数据复制到其中,然后一次又一次地重复,这需要很多时间。因此,切换到打算增长的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}
虽然@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
,因为ArrayList
已被弃用)。此外,您不需要使用Select Object
语句,因为您的csv
已经加载,在该场景中它只处理两次。最大的速度改进不是数千次查询AD,而是将其保存在单个对象中,而主要是不使用[array]
/@()
速度比较:
$L = 1..100000
~70毫秒 ~110毫秒
Measure-Command {$col = @(); foreach ($i in $L) { $col += $i }}
~46秒虽然@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
,因为ArrayList
已被弃用)。此外,您不需要使用Select Object
语句,因为您的csv
已经加载,在该场景中它只处理两次。最大的速度改进不是数千次查询AD,而是将其保存在单个对象中,而主要是不使用[array]
/@()
速度比较:
$L = 1..100000
~70毫秒 ~110毫秒
Measure-Command {$col = @(); foreach ($i in $L) { $col += $i }}
约46秒