Reputation: 132
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
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
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
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