PowerShell Tip from the Head Coach of the 2014 Winter Scripting Games: Design for Performance and Efficiency!

There are several concepts that come to mind when discussing the topic of designing your PowerShell commands for performance and efficiency, but in my opinion one of the items at the top of the list is “Filtering Left” which is what I’ll be covering in this blog article.

First, let’s start out by taking a look at an example of a simple one-liner command that’s poorly written from a performance and efficiency standpoint:

When the previous command is run, all of the PowerShell cmdlets on your machine are returned by the first part of the command prior to the first pipe symbol (the part with the Get-Command cmdlet). They are then piped to the Where-Object cmdlet and then the ones that meet the condition in the where clause are piped to the ForEach-Object cmdlet.

On my Windows 8.1 machine which has the Remote Server Administration Tools installed as well as some other additional cmdlets, that would start out by returning 3696 cmdlets:

posh-tip4a1

This is not exactly what happens, but think of it this way; Store all 3696 of those objects that are returned by the first part of that command in a variable named $Cmdlets:

posh-tip4c

Then filter them down to only the 147 that we’re actually looking for and store those results in a variable named $ADCmdlets:

posh-tip4d

Then send those results to ForEach-Object which iterates through each of those 147 items to retrieve the name for-each one. This step is also unnecessary:

posh-tip4e

Instead of just telling you that this command is inefficient, I’ll show you as well:

posh-tip4f

1.25 seconds doesn’t seem too bad, but let’s run the command 100 times to see how long that takes:

posh-tip4g

It took almost 2 full minutes to run that same command 100 times.

Why was this command written this way? Where did it come from? I copied it off of someones else’s blog who apparently didn’t bother to “Read the Help”. The original command also used cryptic aliases so it’s not an exact copy. Tip #1 was “Read the Help”.

Looking at the help for the Get-Command cmdlet, we can see it has a -Module parameter:

posh-tip4h

By using the Module parameter,  you can filter as far to the left (Filter Left) as possible. In this particular scenario it’s actually possible to filter before the first pipe symbol so you’re only starting out with the exact results that you want (the 147 Active Directory cmdlets):

posh-tip4i

If you wanted just the name of the cmdlets, the command could be written this way:

posh-tip4j

Or this way:

posh-tip4k

This more efficient version of the command completes in about a tenth of the time as the inefficient one:

posh-tip4l

Running this more efficient command 100 times only takes 6 seconds. The inefficient one took almost 2 full minutes:

posh-tip4m

It doesn’t take a rocket scientist to figure out that 6 seconds is a lot more efficient than 2 full minutes 🙂

µ

3 Comments

  1. Boe Prox

    Good stuff, Mike!

    One of my favorite things to show people using Where-Object is how it iterates through all of the items while searching for whatever you are filtering vs. calling the proper parameter and then using Where-Object just to highlight the differences in each approach.

    Get-Command | Where-Object {Write-Verbose “$($_.Name)” -Verbose;$_.Name -eq ‘Get-Process’}

    Get-Command -Name Get-Process | Where-Object {Write-Verbose “$($_.Name)” -Verbose}

    Reply

Leave a Reply

%d bloggers like this: