0

Powershell 新手,随时学习。我每周运行一个报告,要求我从雇主那里获取姓名列表,特别是 userprincipalname 属性的前半部分,检查 AD 中的每个关联帐户,获取帐户详细信息,并将这些详细信息保存到我稍后输入的 CSV Excel。

我的列表通常有 5000 个名字长,所有用户都分散在不同 OU 的不同级别。我最初使用的是下面的代码,但是通过将我的 OU 缩小到我的本地办公室(OU=Level_1),我注意到它很快,但只找到了处于 1 级(大约 80%)用户的用户,并且省略了其他所有人。我停止指定级别 1 并从级别 2 开始,它运行得慢得多,但发现了更多。从第 3 级开始,每个人都找到了,但现在每个 $user 需要 4-5 秒 $users... 总共需要几个小时。

我 ::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"

编辑:下面的乔希有不同的方式来做同样的事情:

  For every $user in $users, look in the Level_1 OU
    if User is found, append Employee_Details.CSV
    else send the user to a new array $Level_2.
  For every $user in $Level_2, look in the Level_2 OU
    if User is found, append Employee_Details.CSV,
    else send the user to a new array $Level_3.
  For every $user in $Level_3, look in the Level_2 OU
    if User is found, append Employee_Details.CSV,
    else send the user to a new array $Level_4.

到目前为止,这似乎是一个很好的方法,但还没有完全做到。

$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)
}
4

1 回答 1

0

所以我试图思考如何做到这一点,我认为最好的方法是尝试针对 1 级 OU 搜索所有 AD 用户。如果用户不在该 OU 中,则将它们添加到包含不在 1 级 OU 中的所有用户的数组中。

此时,您将运行另一个 ForEach 循环来尝试 2 级 OU,然后是 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)
}

编辑:所以你在下面看到的问题是我$Level_2_Catch = @()在 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)
}
于 2021-12-05T18:29:17.893 回答