【问题标题】:Powershell querying users in Active DirectoryPowershell 在 Active Directory 中查询用户
【发布时间】:2019-01-26 21:35:18
【问题描述】:

我很难找到一种更有效的方式从 AD 中查询信息。就目前而言,我从我们的学生信息系统中导入了一个活跃用户的.csv 文件。然后我想从 AD 创建一个新的.csv 活动用户信息文件。因此,我正在查询每个用户(大约 1 万名学生)的 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}

【问题讨论】:

    标签: powershell csv active-directory


    【解决方案1】:

    我认为,与其用Get-ADUser 查询每个用户,不如一次性获取所有具有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}
    

    【讨论】:

      【解决方案2】:

      虽然@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>,因为不推荐使用ArrayList) .此外,您不需要使用 Select-Object 语句,因为您的 csv 已经加载,并且在这种情况下它只会处理两次。最大的速度改进不是查询 AD 数千次,而是将其保存在单个对象中,但主要是不使用 [array]/@()


      速度比较:

      $L = 1..100000
      

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

      ~70ms

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

      ~110ms

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

      ~46 秒

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-29
        • 1970-01-01
        • 1970-01-01
        • 2023-03-26
        • 2010-09-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多