PowerShell Pipeline Binding Trick

Last time we explored in graphic detail what happens inside a PowerShell pipeline. I want to take this a step further, because there is a little more going on and once you understand it, you'll be able to write incredible PowerShell expressions. Let's go back and look at a service example:

The first part of the pipeline retrieves the Windows Search service object, which is piped to a second cmdlet, Stop-Service, which does its thing. But why did this work? Not every cmdlet supports pipeline input. Let's look at cmdlet help:

PS C:\> help stop-service -full

As you look at the different parameters, you'll see that some accept pipeline input and some don't. For the sake of discussion, look at just the Name parameter:

PS C:\> help stop-service -Parameter Name

As you can see, it accepts pipelined input:

Accept pipeline input? true (ByValue, ByPropertyName)

This parameter uses what is referred to as pipeline binding. In this particular case it will bind either ByValue or ByPropertyName. Here's what this means to you.

The ByValue reference essentially means any object that the cmdlet sees it will try to treat as a service name. Here's an example:

The two strings, wsearch and wuauserv are piped to Stop-Service. The cmdlet looks at the incoming objects, takes their values and binds them to the -Name parameter. Here's another example using the Restart-Service cmdlet which also uses pipeline binding:

The text file is simply a list of service names that are piped to Restart-Service.

The other way to accomplish pipeline binding is by PropertyName. In other words, the cmdlet looks at the incoming object and if it sees a matching property name for the parameter, it binds. The object can be anything. Here's a CSV file I want to import into PowerShell:

I can't pipe this directly to any of the service cmdlets because there are no properties that can be bound to any parameters. Here's the trick: Use Select-Object with a hash table and create a new property on the fly:

The hash table creates a new property called "Name" that will bind to the Name parameter in Restart-Service. The value will be the value of the "svc" property of each object in the pipeline. Alternatively, I could have used ForEach-Object:

but I like using Select-Object, especially if I want to bind multiple properties to multiple parameters. Are you beginning to see possibilities?

You'll also sometimes run into this situation with cmdlets that write an object to the pipeline with a property name that can't be used without a little magic. For example, Get-ADComputer uses -name but all the cmdlets you'd like to pipe to are expecting -Computername. In these situations, use my magic trick.

About the Author

Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.