2017-08-24 Don’t use Get-ADUser every time! Or maybe use?
When it comes to do some queries in the AD I often see that others advise
“Don’t call Get-ADUser every time. Better get everything local and query against it.”
Edit: I meant doing it in a script in a loop or something like that, not the daily interactive work. That it is faster to work with a local object then to do a Get-ADuser in a loop every time.
Putting the obvious greater AD load aside, how much slower is it?
Let’s test and compare.
Prepare
About 2000 user accounts in AD.
Test scenarios:
- Get-ADUser each time
- Get-ADUsers to a variable and then work with that object
- Convert local results to a hashtable, arraylist, deserialize it with to and from csv, to and from json
$ADUsers = Get-ADUser -Filter * # AD Results
$ADUsersHT = @{} # HashTable
[collections.arraylist]$ADUsersArray = @{} # ArrayList
#create ht and array
foreach ($aduser in $ADUsers){
$ADUsersHT.Add($aduser.Samaccountname,$aduser)
$null = $ADUsersArray.Add($aduser)
}
$ADusersCSV = $ADUsers | ConvertTo-CSV | ConvertFrom-Csv # CSV
$ADUsersJSON = $AdusersCSV | ConvertTo-Json | ConvertFrom-Json # JSON
Get 100 random users from AD to be used in the loop
$users = @()
for ($i=0;$i -lt 100;$i++){
$users += $adusers[$(Get-Random -Minimum 0 -Maximum ($ADUsers.Count - 1))].Samaccountname
}
Tests
Get user from AD by sAMAccountName
- Normal Get-ADUser
Get-ADUser $user
- Where-Object on AD results
$ADUsers | Where-Object samaccountname -EQ $user
- Where method on AD results
$ADUsers.Where({$_.samaccountname -EQ $user})
- Where method with first 1 on AD results
$ADUsersCSV.Where({$_.samaccountname -EQ $user},'First',1)
- Foreach on AD results
foreach ($aduser in $ADUsers){ if ($aduser.samaccountname -eq $user){ $aduser } }
- Foreach with break on AD results
foreach ($aduser in $ADUsers){ if ($aduser.samaccountname -eq $user){ $aduser break } }
- Where-Object on CSV results
$ADUsersCSV | Where-Object samaccountname -EQ $user
- Where method on CSV results
$ADUsersCSV.Where({$_.samaccountname -EQ $user})
- Where-Object on JSON results
$ADUsersJSON | Where samaccountname -EQ $user}
- Foreach on JSON
foreach ($aduser in $ADUsersJSON){ if ($aduser.samaccountname -eq $user){ $aduser } }
- Foreach with break on JSON
foreach ($aduser in $ADUsersJSON){ if ($aduser.samaccountname -eq $user){ $aduser break } }
- Where-Object on ArrayList
$ADusersArray | Where-Object samaccountname -EQ $user}
- HashTable
$ADUsersHT["$user"]
Results
Average results from 10 runs each 100 users in a loop. (Given time for 100 user queries)
- Normal Get-ADUser - 800 ms
- Where-Object on AD results - 9843 ms
- Where method on AD results - 4895 ms
- Where method with first 1 on AD results - 2526 ms
- Foreach on AD results - 2066 ms
- Foreach with break on AD results - 1094 ms
- Where-Object on CSV results - 12571 ms
- Where method on CSV results - 2877 ms
- Where-Object on JSON results - 12513 ms
- Foreach on JSON - 860 ms
- Foreach with break on JSON - 463 ms
- Where-Object on ArrayList - 12381 ms
- HashTable - 7 ms
Summary
Worst times on Where-Object. It was very slow. ~ 11827 ms
$ADUsers | Where samaccountname -EQ $user
The Where method was faster. ~ 3886 ms
$ADUsersCSV.Where({$_.samaccountname -EQ $user})
It got better with First option. ~ 1948 ms
$ADUsersCSV.Where({$_.samaccountname -EQ $user},'First',1)
Foreach, with break if applicable, is the right way to deal with objects if you already burned them in memory. 1094 ms
foreach ($aduser in $ADUsers){
if ($aduser.samaccountname -eq $user){
$aduser
break
}
}
If a deserialized object is something you can live with then it gets a tick faster.
$ADusersCSV = $ADUsers | ConvertTo-CSV | ConvertFrom-Csv
foreach ($aduser in $ADUsersCSV){
if ($aduser.samaccountname -eq $user){
$aduser
break
}
}
Still 860 ms and 463 ms with break on deserialized objects.
Why not stick to get the user direct with Get-Aduser if the AD guys are not knocking at your door? It is fast ~ 800 ms.
Get-ADUser $user
But nothing beats a HashTable. It is super-fast - 7 ms.
It was 66 times faster than the best from the rest and 1795 times faster than the worst result.
$ADUsersHT["$user"]
The HashTable is not something for every use case but is worth to consider when you want to speed up things.
Source code
Code on pastebin
Leave a Comment