In a current project where I use the PowerShell Management Agent from Søren Granfeldt to import information from a large LDAP catalog I discovered that there are some performance problems if you use PowerShell the incorrect way. One of these things is the use of ForEach vs ForEach-Object when enumerating a large collection of objects.
Searching the web I found this article from Anita, that helped me.
The results was stunning!
Look at this scenario where I search for objects in the LDAP catalog and the search returns +20 thousand objects.
I got $Response.Entries.Count
is 21897
I then use the Measure-Command to compare the ForEach with the ForEach-Object way of iterating the objects.
First let’s see how the generic ForEach-Object{} is doing.
(Measure-Command{$Response.Entries | ForEach-Object{$_.DistinguishedName} }).TotalMilliseconds
Resulted in: 1020 milliseconds
And then let’s see how ForEach(){} is doing when defining the type of object in the collection
Defining the entry object type like this
[System.DirectoryServices.Protocols.SearchResultEntry]$entry
and then measuring the result
(Measure-Command{ForEach($entry in $Response.Entries){$entry.DistinguishedName} }).TotalMilliseconds
Resulted in: 98 milliseconds
A performance factor of 10!.
And since a few of my collections in this project was actually returning more than 200 thousand objects you can imagine that I actually was able to see some effect.
Nice write up!
Here is another subtle way to improve loops in PowerShell.
Make Your PowerShell For Loops 4x Faster [http://www.dougfinke.com/blog/index.php/2011/01/16/make-your-powershell-for-loops-4x-faster/]
Doug