AtomicReaction
AtomicReaction

Reputation: 132

Getting better performance when searching for accounts

I'm trying to find an efficient way to query large amounts of user accounts in ActiveDirectory, and I'm having a bit of an issue.

I have a script that goes through a file exported from another employee management program grabbing employeeIDs, which I then search for in ActiveDirectory. Every user account has an associated employeeID, and I use whether or not a certain ID is found in A/D to show whether an account should be created or deleted (if in file but not A/D, create; if in A/D but not file, delete). My problem is that I cannot find an efficient way to do this.

My old method was to search for every employeeID one at a time with Get-ADUser, but this was very slow. I've also tried pulling down all the non-system accounts, and then using Where-Object on the list to filter out the account that matches. This also gets very slow with large amounts of accounts because Where-Object is checking every single account in my array of accounts.

I think there must be a faster way to do this, since I'm able to slam a -contains on the attribute I'm trying to match and get a response for every ID within a minute or so, versus the 20 it takes to run a where-object. Any advice?

Some notes:

I have already preprocessed the IDs coming from the file and the IDs in ActiveDirectory to make sure there are no duplicates, so only getting the first result is fine.

Old Method (simplified with processing code taken out):

$csv = Import-CSV -Path $someFile
Foreach($line in $csv){
    $DoesAccountExist = Get-Aduser -filter {employeeID -eq $line.employeeID}
    }

Working in memory method:

$csv = Import-CSV -Path $someFile
$Users = Get-Aduser -filter *
$NonSystemUsers = $users | Where-Object {$_.employeeID -match $employeeIDPattern}

#This is the part that is slow
foreach($line in $csv){
    $DoesAccountExist = $NonSystemUsers | Where-Object {$_.employeeID -eq $line.employeeID}
    }

Upvotes: 3

Views: 3869

Answers (3)

mjolinor
mjolinor

Reputation: 68341

I'd start by doing one bulk query of AD, and building a hash table (Key = EmployeeID, Value = DN), and then work from that.

$hash = @{}

Get-ADUser -Properties EmployeeID -Filter * |
 foreach {$hash[$_.EmployeeID] = $_.DistinguishedName}

 $csv = Import-CSV -Path $someFile
 Foreach($line in $csv){
  $DoesAccountExist = [bool]($hash[$line.employeeid])
}

$hash[$line.employeeid] will return the DN of the user that belongs to that employeeid if it's in the table.

Upvotes: 5

websch01ar
websch01ar

Reputation: 2123

The quickest method you have here is to join the two objects $csv and $users based upon the employeeID field present in both. I have my own function named JoinObjects, which I cannot share unless I wish to get in trouble. However, the blog post below has an example that is nearly like my own.

http://blogs.msdn.com/b/powershell/archive/2012/07/13/join-object.aspx

Upvotes: 0

user189198
user189198

Reputation:

This script create a HashTable of users, and then simply compares the employeeID, from the CSV file, against the HashTable's Keys property. This is far more efficient than calling Where-Object for each iteration.

$csv = Import-CSV -Path $someFile;
$Users = Get-Aduser -Filter *;
# Convert NonSystemUsers into a HashTable that can be indexed into
$NonSystemUsers = $users | Where-Object {$_.employeeID -match $employeeIDPattern} | % { @{ $_.employeeID = $_; } };

foreach($line in $csv){
    # Check if Dictionary keys contains the employee ID.
    # This is MUCH more efficient than calling Where-Object for each user
    $DoesAccountExist = $NonSystemUsers.Keys -contains $Line;
}

Upvotes: 3

Related Questions