Renaissance Sculpture – the PowerShell way!

PowerShell, like most Microsoft technologies, gives us more than one way to do the same thing. Sometimes that’s good news: it’s nice to use software that can compensate for differences in style from one user to another. Other times, it creates an issue.

Sometimes one way to do something is less effective than another — sometimes in subtle ways. The wrong choice might add a few extra seconds to a job that takes a few minutes and many minutes to a job that might take hours. Those small changes add up over time. Which question do you want your boss to ask: “How does she manage to get everything done with time to spare?” or “Why is he always running behind schedule?”

One of PowerShell’s most valuable features is pipelining. Borrowed from UNIX, pipelining allows manipulation of vast amounts of data with elegantly short statements. In one programming statement, data can be retrieved, filtered, sorted, acted upon, reported on, and sent to your inbox. But that great strength masks one of its greatest vulnerabilities. Great quantities of information can be processed quickly. But is it as quickly as it could be?

Consider the following piece of PowerShell code.

Get-WMIObject Win32_Service | Where-Object {$_.Name –eq “Spooler”} | Start-Service

It’s a straightforward piece of code that starts the Print Spooler service. It processes in a fifth of a second — that’s quick! Get the service and start it… simple, right?

Not so fast. Think carefully about what happens in this code. The first segment, before the first pipe, does not retrieve one service — it retrieves all the services. Now, I’ve got 167 services currently present on my laptop (running Windows 8 Consumer Preview, by the way). 167 objects gurgle down the pipeline into Where-Object. That cmdlet takes those 167 objects and produces an output of a grand total of…

…one object — which gets started by Start-Service.

I’m reminded of a quote attributed to the sculptor Michelangelo.

“In every block of marble I see a statue; see it as plainly as though it stood before me, shaped and perfect in attitude and action. I have only to hew away the rough walls that imprison the lovely apparition to reveal it to other eyes, as mine see it.”

My call to Get-WMIObject serves up a big ol’ block o’ marble. 167 services are described by a lot of data. The Where-Object filter starts ‘hewing away’ pieces from that Statue-of-David-sized block of marble until it gets down to the size of a small figurine, which it puts on the pipeline. What happens to the rest of that unused marble? Jacopo I’Indaco (one of Michelangelo’s underappreciated assistants) sweeps it into a dustpan while sobbing quietly to himself.

Is there a better way? There certainly is. Get-WMIObject has a –filter parameter, which allows us to pass a description of what we are interested in to the WMI service. WMI tries to act like a big database of information about a Windows system that you can query — but in reality it isn’t. WMI passes your request to a piece of software called a provider. That’s important because WMI providers — the components that extract the data we need — are specialists in retrieving data from their areas of expertise. They can retrieve data in a fast, targeted way. Here’s a piece of code with identical output, but with a processing time of 120 milliseconds.

Get-WMIObject –filter “Name = ‘Spooler’” | Start-Service

What’s the difference? Consider visiting a library. I live in the Chicago area, and the biggest library in the area in the Harold Washington Library Center in downtown Chicago. This massive, ten-story facility circulated 77,000 books in January of this year alone. Imagine visiting the HWLC with a burning need to read a particular book. Unfortunately, you are too shy to ask for help finding it. The good news is that it is still very possible to find your book. All that’s necessary is to check each book, on each shelf, in each stack of shelves, in each row of stacks, on each floor until you find it — or worse, until you get to the top floor and find it isn’t there at all. It’s beyond obvious that you would have saved time by asking a librarian, who with a quick check of an index could have pointed you immediately to the correct floor, stack, and shelf — or else told you not to bother, because the library doesn’t have the title.

The librarian is the WMI –filter parameter. The underlying provider code that retrieves my list of services has expert knowledge about those services. It can intelligently target the data that I need. That’s handy when finding my one service in a list of 167. It’s an even more valuable when targeting hundreds or even thousands of objects.

By contrast, Where-Object is the wallflower on the sixth floor of the library still searching for the latest Tom Clancy novel in the horticulture section. While blindfolded. Yeah — he’ll be a while.

Maybe you’re thinking, “big deal, Mike — you saved 80 milliseconds. Don’t spend it all in one place.” But consider the percentage improvement in the speed of that data retrieval (calculated with the very handy Measure-Command cmdlet, incidentally). Cutting a 200ms job down to 120ms is a savings of 40%! How’d you like to take an hour-long task and cut it down to 36 minutes? Or take something that runs all day and shave off 3 hours? Perhaps more dramatically, isn’t it important to you to make sure that jobs that you hope to complete in 36 minutes don’t take an hour? Here’s how: look for opportunities to filter objects without having to resort to Where-Object.

I like to think that if Michelangelo were a PowerShell programmer, he’d have said this: “I see a statue in my mind, and… then I buy a statue just like it that somebody else carved. Then I show it to everybody and say that it’s mine. Because that leaves me more time to do things I really care about.”

In this article

Join the Conversation

1 comment

  1. Mike Hammond Reply

    Need help ‘hewing away’ at the marble of your data? Feel free to ask questions here!