One of Windows PowerShell’s greatest features is its ability to move, transform, filter, and format data by means of the language’s object pipeline. My goal for you in this article is to teach you how the PowerShell pipeline works under the hood so you can use PowerShell more effectively in your administration.

Timothy Warner

Timothy Warner is a Microsoft Cloud and Datacenter Management Most Valuable Professional (MVP) who is based in Nashville, TN. Check out his Azure and Windows Server video training at Pluralsight, and feel free to reach out to Tim via Twitter.

Latest posts by Timothy Warner (see all)

My test environment is a freshly installed Windows 10 Enterprise workstation running its default Windows PowerShell v5 build:

 Pipeline basics ^

UNIX and Linux have used the pipeline for many, many years. For instance, we can run the following pipeline on my Linux server to search currently running Firefox browser processes:

The first part of that pipeline retrieves a text table of currently running processes. The pipe character (|) feeds that text output into the Global Regular Expression Print (grep) utility, filtering the input for string matches on “firefox.”

What is significant about Windows PowerShell, which uses the same basic pipeline, is that in PowerShell all data is represented as “three-dimensional” objects instead of flat text. Thus, PowerShell grants us so much more power as administrators! For example, try out the following command:

Not only does the Get-Member output tell us that Get-Service returns ServiceController objects, but we can also perform many actions (methods) and view/edit metadata (properties) of those objects. You simply can’t do all that with flat text in Linux!

“Bookend” PowerShell commands ^

The PowerShell development team at Microsoft engineered many core commands to fit together in much the way LEGO bricks connect. Take the service commands, for example:

You’ve probably used a pipeline like the following dozens of times to stop a service:

Yes, I know we can use Stop-Service on its own, but bear with me here. Did you ever wonder exactly why the pipeline works? Well, under the hood we have a dynamic called parameter binding going on. Specifically, PowerShell commands can bind parameters between pipeline elements in one (or both) of two ways:

  • ByValue: The data type
  • ByName: A simple parameter name

You may be thinking, “What in the world are you talking about, Tim?” Let’s examine the help for Get-Service, paying particular attention to the Outputs section. We’ll fetch the online version of the help file by running the following command:

If you scroll down to Outputs, note the following text:

By default, Get-Service returns ServiceController objects and “feeds” them to the next command in the PowerShell pipeline.

Now, let’s examine the Stop-Service help and focus on its Inputs:

You can pipe a service object or a string that contains the name of a service to Stop-Service.

We see that Stop-Service fully “expects” ServiceController objects as input, but it would accept string objects in a pinch.

Parameter binding - ByValue ^

Continuing our previous discussion of the Get-Service | Stop-Service pipeline, we can drill deeper into how outputs and inputs click together by studying a cmdlet’s parameters.

For example, Stop-Service has a parameter named InputObject:

Notice that the InputObject parameter expects ServiceController objects. Note also that the Accept pipeline input? field says True (ByValue). If Get-Service puts ServiceController objects into the pipeline and Stop-Service catches those objects, then we have a seamless data fit. Beautiful!

Parameter binding - ByPropertyName ^

Now, if you studied all the Stop-Service parameters, you may have noticed -Name:

Note that the parameter’s attribute table says that -Name is a required parameter in position 1. That means we can do this:

and it will have the same effect as doing this:

Going further, however, we see that Accept pipeline input? says true(ByValue,ByPropertyName). Whoa—what’s up with that?

Let’s run a little experiment. Create a simple file called spooler.csv that contains the following data:

Next, try the following pipeline, making sure that the Spooler service is started prior to doing so and run the following command on a PowerShell command with administrator rights:

Did it work? You should find that it did. I’ll show you how to prove it in the last section of today’s tutorial, but we can make the reasonable assumption that (a) The Import-Csv command put something other than ServiceController objects into the pipeline, and therefore (b) Stop-Service used its -Name parameter to find a matching parameter called -Name in the input.

Yes, property-based parameter binding is as low-tech and simple as looking for a matching parameter name!

We can demonstrate this by editing our spooler.csv file to look like the following:

In this tiny CSV, we have two column headings (Service and AuditState) and a single row of data.

In practice, you should find that the previous pipeline fails with the following red error output:

The main bit we’re concerned with is this:

The take-home message here is that PowerShell will first attempt a pipeline bind by value, and then, failing that, it will look for a matching parameter name between itself and the incoming objects. Specifically, PowerShell took the first (column name row in the CSV) as the property names.

Thanks to Jeff Hicks, I have a nice trick for visualizing how PowerShell performs pipeline parameter binds.

We’ll use the nifty Trace-Command cmdlet for this purpose. We’ll employ three of its parameters:

  • Name: We’ll limit the debug output to parameter binding events.
  • PSHost: This prints the output to the PowerShell host.
  • Expression: Here, we simply dump in our pipeline to test.

Try out the following statement on a PowerShell  console with administrator rights:

Your eyes will probably cross when you see the output volume, but we should be able to make sense of it. Look at the following annotated screenshot and I’ll call out the important statement:

Tracing a PowerShell pipeline

Tracing a PowerShell pipeline

You can see that PowerShell was successful in binding the outgoing ServiceController objects to the Stop-Service cmdlet’s InputObject parameter.

To finish up, correct your spooler.csv file to label the first column heading Name and invoke the following trace:

Once again, you’ll get an entire screen of output, but we are concerned with only the following line that I highlighted in the screenshot below:

Trace-Command shows how PowerShell binds pipeline objects

Trace-Command shows how PowerShell binds pipeline objects.

Here, we see a successful bind between the incoming string data from Import-Csv to the Name parameter of Stop-Service.

I hope that your newfound insight into the PowerShell pipeline makes troubleshooting easier for you. Take care!

Join the 4sysops PowerShell group!


Leave a reply

Your email address will not be published. Required fields are marked *


© 4sysops 2006 - 2019


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account