Как перебрать 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)
}
Редактировать: Таким образом, проблема, которую вы видели ниже, заключалась в том, что я поместил строку, чтобы сделать пользовательский массив перехвата (т.е.:
Я только что попробовал это в тестовой среде, и это сработало, как и предполагалось, дайте мне знать, если это сработает и для вас:
$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)
}