Как перебрать OU с помощью Get-ADUser -searchbase?

Новичок в PowerShell, изучаю его на лету. Я еженедельно запускаю отчет, который требует, чтобы я получил список имен от моего работодателя, в частности первую половину атрибута userprincipalname, проверял каждую связанную учетную запись в AD, получаю данные учетной записи и сохраняю эти данные в CSV, который я позже ввожу в Excel.

Мой список обычно состоит из 5000 имен, и все пользователи разбросаны по разным подразделениям на разных уровнях. Первоначально я использовал приведенный ниже код, но, сузив количество подразделений до локального офиса (OU=Level_1), я заметил, что он работает быстро, но обнаружил только пользователей, которые находятся на Уровне 1 (около 80%) пользователей, и опущены все остальные. Я перестал указывать уровень 1 и начал с уровня 2, и он работал намного медленнее, но нашел еще несколько. Начиная с уровня 3 нашел всех, но теперь занимает 4-5 секунд на каждого пользователя в $users... несколько часов в целом.

I ::think:: есть способ сделать это быстрее, указав операторы if/else:

        For every $user in $users, look in the Level_1 OU
    if User is found, append Employee_Details.CSV, move to next $user
    else look in the Level_2 OU
        if User is found, append Employee_Details.CSV, move to next $user
        else look in the Level_3 OU
          if User is found, append Employee_Details.CSV, move to next $user
          else look in the Level_4 OU
            if User is not found, write-out "User Not Found"

Может ли кто-нибудь помочь мне ускорить это?

      $users = (Import-csv C:\Users\mickey.mouse\Desktop\userprincipalname_List.txt).userprincipalname
$count = 0
$start = Get-Date

foreach ($user in $users) {
    $count++
    
    # calculate percent complete
    $percentComplete = ($count / $users.Count) * 100

    # Define parameters for Write-Progress
    $progressParameters = @{
        Activity = "Searching AD for userprincipalnames on list [$($count)/$($users.Count)] $($secondsElapsed.ToString('hh\:mm\:ss'))"
        Status = 'Processing'
        CurrentOperation = "Writing AD data for: $user to file"
        PercentComplete = $percentComplete
    }

    # if we have an estimate for the time remaining, add it to the Write-Progress parameters
    if ($secondsRemaining) {
        $progressParameters.SecondsRemaining = $secondsRemaining
    }

    # Write the progress bar
    Write-Progress @progressParameters

    # Insert code to be performed in each iteration of the array here
    Get-ADUser -searchbase "OU=Level_1,OU=Level_2,OU=Level_3,OU=Level_4,DC=Alpha,DC=Bravo,DC=Charlie" -Filter "userprincipalname -like '*$user*'" -properties * | select-object employeeid, name, title, mail, description, lastlogondate, userprincipalname | 
    Export-CSV C:\Users\mickey.mouse\Desktop\Employee_Details.csv -NoTypeInformation -append


    # estimate the time remaining
    $secondsElapsed = (Get-Date) – $start
    $secondsRemaining = ($secondsElapsed.TotalSeconds / $count) * ($users.Count – $count)
}

1 ответ

Итак, я пытался придумать, как это сделать, и я думаю, что лучшим способом было бы попытаться найти всех пользователей AD по OU уровня 1. Если пользователь не входит в эту OU, добавьте его в массив, содержащий всех пользователей, не входящих в OU уровня 1.

В этот момент вы запустите еще один цикл ForEach, чтобы попробовать OU уровня 2, затем уровень 3 и так далее.

Я изменил ваш сценарий, чтобы сделать это для уровня 1 и уровня 2. Я не тестировал его, поэтому дайте мне знать, если это поможет, или если у вас есть какие-либо вопросы или проблемы с его запуском:

      $Users = (Import-csv C:\Users\mickey.mouse\Desktop\userprincipalname_List.txt).userprincipalname
$Count = 0
$Start = Get-Date

foreach ($User in $Users) {
    $Count++
    $PercentComplete = ($Count / $Users.Count) * 100
    $ProgressParameters = @{
        # Modified Activity to reflect changes
        Activity = "Searching Level 1 OU for userprincipalnames on list [$($count)/$($users.Count)] $($secondsElapsed.ToString('hh\:mm\:ss'))"
        Status = 'Processing'
        CurrentOperation = "Writing AD data for: $user to file"
        PercentComplete = $PercentComplete
    }
    if ($SecondsRemaining) {
        $ProgressParameters.SecondsRemaining = $SecondsRemaining
    }
    Write-Progress @ProgressParameters

    # Create a variable to catch Users not in Level_1_OU
    $Level_1_Catch = @()
    
    # Clear Level_1_User variable
    $Level_1_User = $null

    # Try to perform Get-ADUser, if not found SilentlyContinue
    $Level_1_User = Get-ADUser -searchbase "OU=Level_1,OU=Level_2,OU=Level_3,OU=Level_4,DC=Alpha,DC=Bravo,DC=Charlie" -Filter "userprincipalname -like '*$user*'" -properties * -ErrorAction SilentlyContinue | select-object employeeid, name, title, mail, description, lastlogondate, userprincipalname 
    
    # If user is detected in $Level_1_OU, export to csv
    If ($Level_1_User -ne $null){
        $Level_1_User | Export-CSV C:\Users\mickey.mouse\Desktop\Employee_Details.csv -NoTypeInformation -append
    }

    # If not, add the user to the $Level_1_Catch
    Else{
     $Level_1_Catch += $User    
    }
    $SecondsElapsed = (Get-Date) – $Start
    $SecondsRemaining = ($secondsElapsed.TotalSeconds / $Count) * ($Users.Count – $Count)
}

$Count = 0
foreach ($User in $Level_1_Catch) {
    $Count++
    $PercentComplete = ($Count / $Users.Count) * 100
    $ProgressParameters = @{
        # Modified Activity to reflect changes
        Activity = "Searching Level 2 OU for userprincipalnames on list [$($count)/$($users.Count)] $($secondsElapsed.ToString('hh\:mm\:ss'))"
        Status = 'Processing'
        CurrentOperation = "Writing AD data for: $user to file"
        PercentComplete = $PercentComplete
    }
    if ($SecondsRemaining) {
        $ProgressParameters.SecondsRemaining = $SecondsRemaining
    }
    Write-Progress @ProgressParameters

    # Create a variable to catch Users not in Level_2_OU
    $Level_2_Catch = @()
    
    # Clear Level_2_User variable
    $Level_2_User = $null

    # Try to perform Get-ADUser, if not found SilentlyContinue
    $Level_2_User = Get-ADUser -searchbase "OU=Level_2,OU=Level_3,OU=Level_4,DC=Alpha,DC=Bravo,DC=Charlie" -Filter "userprincipalname -like '*$user*'" -properties * -ErrorAction SilentlyContinue | select-object employeeid, name, title, mail, description, lastlogondate, userprincipalname 
    
    # If user is detected in $Level_1_OU, export to csv
    If ($Level_2_User -ne $null){
        $Level_2_User | Export-CSV C:\Users\mickey.mouse\Desktop\Employee_Details.csv -NoTypeInformation -append
    }

    # If not, add the user to the $Level_2_Catch
    Else{
     $Level_2_Catch += $User
    }
    $SecondsElapsed = (Get-Date) – $Start
    $SecondsRemaining = ($secondsElapsed.TotalSeconds / $Count) * ($Users.Count – $Count)
}

Редактировать: Таким образом, проблема, которую вы видели ниже, заключалась в том, что я поместил строку, чтобы сделать пользовательский массив перехвата (т.е.: ) внутри ForEach, который очищал его каждый раз, когда он зацикливался.

Я только что попробовал это в тестовой среде, и это сработало, как и предполагалось, дайте мне знать, если это сработает и для вас:

      $Users = (Import-csv C:\Users\mickey.mouse\Desktop\userprincipalname_List.txt).userprincipalname
$Count = 0
$Start = Get-Date

# Create an array to catch Users not in Level_1_OU
## This needs to be outside of the ForEach loop, otherwise it clears the array each time it runs.
$Level_1_Catch = @()

foreach ($User in $Users) {
    $Count++
    $PercentComplete = ($Count / $Users.Count) * 100
    $ProgressParameters = @{
        # Modified Activity to reflect changes
        Activity = "Searching Level 1 OU for userprincipalnames on list [$($count)/$($users.Count)] $($secondsElapsed.ToString('hh\:mm\:ss'))"
        Status = 'Processing'
        CurrentOperation = "Writing AD data for: $user to file"
        PercentComplete = $PercentComplete
    }
    if ($SecondsRemaining) {
        $ProgressParameters.SecondsRemaining = $SecondsRemaining
    }
    Write-Progress @ProgressParameters

    # Clear Level_1_User variable
    $Level_1_User = $null

    # Try to perform Get-ADUser, if not found SilentlyContinue
    $Level_1_User = Get-ADUser -searchbase "OU=Level_1,OU=Level_2,OU=Level_3,OU=Level_4,DC=Alpha,DC=Bravo,DC=Charlie" -Filter "userprincipalname -like '*$user*'" -properties * -ErrorAction SilentlyContinue | select-object employeeid, name, title, mail, description, lastlogondate, userprincipalname 
    
    # If user is detected in $Level_1_OU, export to csv
    If ($Level_1_User -ne $null){
        $Level_1_User | Export-CSV C:\Users\mickey.mouse\Desktop\Employee_Details.csv -NoTypeInformation -append
    }

    # If not, add the user to the $Level_1_Catch
    Else{
     $Level_1_Catch += $User    
    }
    $SecondsElapsed = (Get-Date) – $Start
    $SecondsRemaining = ($secondsElapsed.TotalSeconds / $Count) * ($Users.Count – $Count)
}

$Count = 0
# Create an array to catch Users not in Level_2_OU
## This needs to be outside of the ForEach loop, otherwise it clears the array each time it runs.
$Level_2_Catch = @()
foreach ($User in $Level_1_Catch) {
    $Count++
    $PercentComplete = ($Count / $Users.Count) * 100
    $ProgressParameters = @{
        # Modified Activity to reflect changes
        Activity = "Searching Level 2 OU for userprincipalnames on list [$($count)/$($users.Count)] $($secondsElapsed.ToString('hh\:mm\:ss'))"
        Status = 'Processing'
        CurrentOperation = "Writing AD data for: $user to file"
        PercentComplete = $PercentComplete
    }
    if ($SecondsRemaining) {
        $ProgressParameters.SecondsRemaining = $SecondsRemaining
    }
    Write-Progress @ProgressParameters
    
    # Clear Level_2_User variable
    $Level_2_User = $null

    # Try to perform Get-ADUser, if not found SilentlyContinue
    $Level_2_User = Get-ADUser -searchbase "OU=Level_2,OU=Level_3,OU=Level_4,DC=Alpha,DC=Bravo,DC=Charlie" -Filter "userprincipalname -like '*$user*'" -properties * -ErrorAction SilentlyContinue | select-object employeeid, name, title, mail, description, lastlogondate, userprincipalname 
    
    # If user is detected in $Level_1_OU, export to csv
    If ($Level_2_User -ne $null){
        $Level_2_User | Export-CSV C:\Users\mickey.mouse\Desktop\Employee_Details.csv -NoTypeInformation -append
    }

    # If not, add the user to the $Level_2_Catch
    Else{
     $Level_2_Catch += $User
    }
    $SecondsElapsed = (Get-Date) – $Start
    $SecondsRemaining = ($secondsElapsed.TotalSeconds / $Count) * ($Users.Count – $Count)
}
Другие вопросы по тегам