Question

As part of my job i'm constantly auditing active directory for given properties of cross domain accounts.

I've constructed a powershell script to output information to a CSV based on properties given to the script. This is fine, the script works beautifully for a small list of people however i'm noticing that the script slows down considerably when i provide a big list of users to audit.

This is the script:

    $inputfile = "C:\Powershell\input.txt"
    $users = Get-Content $inputfile

    $audit = Read-Host "Audit Name"
    $csv = ".\output\Audit\$audit.csv"

    $failed = @()

    $serv = @("server1", "server2", "server3")

    if((Test-Path $csv) -eq $true){Remove-Item $csv}

    foreach($domain in $serv)
    {
        $count = $users.Count
        for( $i=0; $i -le $count - 1; $i++ )
        {
            if (($users.Get($i)) -ne "")
            {
                try
                {
                    Write-Host "Checking for $($users.get($i)) on" -NoNewline
                    switch($domain)
                    { # with fancier text for which domain we're searching
                        "server1" {write-host "...Server1" -ForegroundColor Cyan -NoNewline; $domainCsv = "Server1"}
                        "server2" {Write-Host "...Server2" -ForegroundColor White -NoNewline; $domainCsv = "Server2"}
                        "server3" {Write-Host "...Server3" -ForegroundColor Magenta -NoNewline; $domainCsv = "Server3"}
                    }

                    $usr = Get-ADUser -Identity $users.get($i) -Properties $properties -Server $domain | ? { ($_.distinguishedname -notlike '*Suspended*')}
                    if ($usr -ne $null) 
                    {
                        $usr = Get-ADUser -Identity $users.get($i) -Properties $properties -Server $domain | ? { ($_.distinguishedname -notlike '*Deletion*')}
                        if ($usr -ne $null) 
                        {
                            Write-Host "...Found" -ForegroundColor Green

                            $userobj = New-Object PSObject

                            Add-Member -InputObject $userobj -MemberType NoteProperty -Name "User" -Value $($users.Get($i))
                            Add-Member -InputObject $userobj -MemberType NoteProperty -Name "Domain" -Value $domainCsv

                            foreach($prop in $properties) {$userobj | Add-Member -MemberType NoteProperty -Name $prop -Value "$($usr.$prop)"}

                            $userobj | Export-Csv $csv -Append -NoTypeInformation
                        }
                        else
                        {
                            Write-Host "...Pending Delete" -ForegroundColor Red
                            $failed += "$($users.Get($i)),Pending deletion on $domainCsv"
                        }
                    }
                    else
                    {
                        Write-Host "...Suspended" -ForegroundColor Red
                        $failed += "$($users.Get($i)),Suspended on $domainCsv"
                    }                       
                }
                catch [System.Exception]
                {
                    Write-Host "...Not found" -ForegroundColor Red
                    $failed += "$($users.Get($i)),Could not find on $domainCsv"
                } # </Try
            } # </If user ""
        } # </For users
    } # </For Domains
    Add-Content $csv ""
    Add-Content $csv "Those who failed, (Not found or Suspended or Pending deletion)"
    Add-Content $csv ""
    Add-Content $csv "User,Domain"
    foreach($fail in $failed) {Add-Content $csv $fail}
    Write-Host " "
    Write-Host "    Audit saved to $csv" -ForegroundColor Green

What the script does

Gets input file full of users (one name per line) (mostly 20 or so lines but sometimes the input file has been over 200)

user1
user2
user3
user4
user5

goes through each domain

checks if they're in an OU for suspended accounts

checks if they're in an OU for accounts pending deletion

if not in either OU grabs the information and puts it into a PSObject for insertion into a CSV

after its done it lists the accounts it couldnt find or were in an OU that i dont need to worry about.

As i'm quite new to powershell i have no idea if theres a way i can condense parts of the code to be quicker, i have read a few pages on optimizing powershell but the only change i could see was to change

for( $i=0; $i -le $users.count - 1; $i++ )

to

$count = $users.count

for( $i=0; $i -le $count - 1; $i++ )

My question is: How can i improve my script to loop faster when given more users?

Was it helpful?

Solution

As far as I understand your script spent most of the time in Get-ADUser. You call it twice with the same parameters, using $usr you should call it just one time, your script execution time should bedevided by two.

Another thing, I can't find the defenition of $properties in your script, reducing this list can also reduce the network payload.


Test something like this.

$usr = Get-ADUser -Identity $users.get($i) -Properties $properties -Server $domain | ? { ($_.distinguishedname -notlike '*Suspended*')}
if ($usr.distinguishedname -notlike '*Suspended*') 
{
  if ($usr.distinguishedname -notlike '*Deletion*') 
  {
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top