The best part of this entire process—the writing about PowerShell for coming up on nine years—has been the realization of my own mistakes while using PowerShell, and then sharing those. I have an upcoming post on this, but in between preparing and publishing that, I, yes me, made another mistake.
Let’s start with what I wrote first, which is included below. It’s a simple Get-ADComputer
command. By now, we’ve all likely written plenty of these. Looks great right? Does it though?
Get-ADComputer -Filter * -Properties OperatingSystem,Description | Where-Object -Property OperatingSystem -like '*Server*' | Select-Object -Property Name, OperatingSystem | Sort-Object -Property OperatingSystem, Name
Before we move forward and determine what I did wrong, let’s use Measure-Command
to see how long the execution takes for me on my machine.
Measure-Command -Expression { Get-ADComputer -Filter * -Properties OperatingSystem,Description | Where-Object -Property OperatingSystem -like '*Server*' | Select-Object -Property Name, OperatingSystem | Sort-Object -Property OperatingSystem, Name }
Days : 0 Hours : 0 Minutes : 0 Seconds : 4 Milliseconds : 105 Ticks : 41055467 TotalDays : 4.75179016203704E-05 TotalHours : 0.00114042963888889 TotalMinutes : 0.0684257783333333 TotalSeconds : 4.1055467 TotalMilliseconds : 4105.5467
Four seconds. That doesn’t seem too long, but I’m guessing it is based on the way in which the command was written. I never really trust a single test, so let’s set up the above Measure-Command
command to run 10 times consecutively using ForEach-Object
.
1..10 | Foreach-Object { Measure-Command -Expression { Get-ADComputer -Filter * -Properties OperatingSystem,Description | Where-Object -Property OperatingSystem -like '*Server*' | Select-Object -Property Name, OperatingSystem | Sort-Object -Property OperatingSystem, Name } } | Select-Object -Property Seconds, Milliseconds
Seconds Milliseconds ------- ------------ 5 370 5 213 5 311 5 839 4 500 6 234 5 50 5 239 4 656 5 421
Multiple tests and this is closer to a full five seconds per invocation. I don’t know about you, but five seconds in PowerShell is an eternity. We use PowerShell for accuracy, sure, but we use it for efficiency, as well. The quicker the better; we shouldn’t limit ourselves. If you find a mistake then fix it.
Now, let’s use the Filter parameter the way it was intended to be used. Piping to Where-Object
is always going to be slower than using the filtering options provided by the commands we use. Here’s our base command corrected.
Get-ADComputer -Filter {OperatingSystem -like '*Server*'} -Properties OperatingSystem, Description | Select-Object -Property Name, OperatingSystem | Sort-Object -Property OperatingSystem, Name
And here it is wrapped up to be tested 10 times such as we did previously.
1..10 | Foreach-Object { Measure-Command -Expression { Get-ADComputer -Filter {OperatingSystem -like '*Server*'} -Properties OperatingSystem, Description | Select-Object -Property Name, OperatingSystem | Sort-Object -Property OperatingSystem, Name } } | Select-Object -Property Seconds, Milliseconds
Seconds Milliseconds ------- ------------ 1 501 0 922 0 907 0 895 0 930 0 906 1 790 1 534 1 284 0 937
Maybe you’re not worried about those lost seconds. If those aren’t that important, then let it be the possibility that someone’s going to see your failure to be efficient. If I saw this—and again I made this mistake first—I would be concerned that the person writing this code didn’t better explore the command(s) they’re using. If you’re going to use a command, then know it well enough to know how well you’re using it.