Back to top

FREE eBook: The Most USEFUL PowerShell CmdLets and more…

Grab a copy!

PowerShell Pipeline Concept Explained With Awesome Examples

How PowerShell Pipeline Works
Approx Reading Time: 16 minutes

Understanding the pipeline concept in PowerShell was a ‘WoW factor’ moment for me and breaking point to really get the real power of PowerShell. So I highly recommend to everyone to take time and get into PowerShell Pipeline Concept.

I will try in this article to explain the PowerShell Pipeline concept with many awesome examples and even further how you can create your own PowerShell functions and CmdLets that accept pipeline values.

The pipeline is the concept in PowerShell to link together commands with pipeline operator ( | ). That means result from the first command is sent down the pipeline as input to the second command for further processing and the result of the second command is sent down to the pipeline as input to the third command and so on and so forth.

So let’s dive in the world of PowerShell Pipeline so we can completely understand it and use in our future projects.

What Is PowerShell Pipeline – Powerful Effect Of The PowerShell Pipeline Concept

General Pipeline Syntax is as follows:

Command1 | Command2 | Command3

Here is one example and as a result (that you can see on the screenshot), we get the list of Windows Services on the system:

Get-Service | Where-Object -Property Status -EQ Running | Select-Object Name, DisplayName, StartType | Sort-Object -Property StartType, Name
Resultset of PowerShell Pipelining example

Let’s discuss the previous example and how we can build the pipeline depending on the result that we want to achieve.

If we just run the first command, we will get a list of all Windows Services on the machine as a result:

Get-Service
Get-Service CmdLet result

Let’s say we want to see only running Windows Services so one of the solutions for such a requirement is to pipe the result of the first command Get-Service to second command Where-Object (with additional filters) CmdLet. Now, as a result, we get a list of only running Windows Service on the machine

What we have done is sending down the pipeline the result from the first command to the second command for further processing.

Get-Service | Where-Object -Property Status -EQ Running
Where-Object CmdLet and only running windows services

We can continue with the pipeline concept further. For example, we do not want as a result to have columns: Status, Name, and DisplayName but rather the following columns: Name, DisplayName, StartType.

We can achieve that if the result from the second command Where-Object CmdLet sends again down the pipeline to the third command, in this case, Select-Object CmdLet and specify which columns we want in the resultset:

Get-Service | Where-Object -Property Status -EQ Running | Select-Object Name, DisplayName, StartType

Finally, we could be unsatisfied with the sorting of the result and maybe we want to have the result sorted by the StartType column first and Name column second. So again we send the result down the pipeline to the fourth command, in this case, Sort-Object CmdLet.

Get-Service | Where-Object -Property Status -EQ Running | Select-Object Name, DisplayName, StartType | Sort-Object -Property StartType, Name
Resultset of PowerShell Pipelining example

NOTE: To me, this sending the results down the pipeline in PowerShell looks the same as sending the “materials” down the production line until we get the shape and form of the final product.

PowerShell Pipeline Concept vs Product Manufacturing (Analogy)

I used to work in a biscuits factory so the PowerShell Pipeline concept is like a production line in a factory. Here is an example of the production line in biscuits factory:

  • mix the dough (first command),
  • then send that dough further on the conveyer into the oven to bake (the second command – bake the dough),
  • and biscuit’s baked base we send further into the jelly station to put some orange jelly on the top (the third command – jelly the biscuits),
  • then we can shower the biscuits with chocolate (the fourth command – chocolate the biscuits),
  • and send further for packaging to wrap and package the biscuits (the fifth command – package the biscuits).

In the end, we get our final product ready to be put on the shelves for the consumers. The same thing is with commands in PowerShell send through the pipeline where we shape and customize our resultset until we get the final resultset that we want to present.

Why PowerShell Pipeline Concept Is So Efficient

Before we dive into how PowerShell Pipeline Concept works lets just quickly look at what PowerShell does for us with pipelining.

From the previous section, we know that the Pipeline “|” links commands and sends the result from the previous to the next command.

In some other programming languages, we do not have such a level of efficiency as we have with pipelines in PowerShell. Very often in the other programming languages, we get the result and if we want to process the result further on the row by row basis we use concepts like cursors where we fetch one row of result at a time and do the processing on that row and continue to the next row until we reach the end of all rows. As we know such cursor processing is very slow and inefficient in most cases.

Let’s go back to the previous section example and look first two commands in the pipeline:

Get-Service | Where-Object -Property Status -EQ Running 

With Get-Service CmdLet we get all the Windows Services on our system so that is resultset with many rows or objects as called in PowerShell and then we use Where-Object CmdLet to filter out some rows/objects from the first resultset just by stating the name of the object property (Status column of resultset) and the criteria to filter out (we want only services that have Status equal “Running”) that means only running services are shown in the second resultset.

NOTE: We did not create any loop to go object by object in the first resultset and save only the objects that represent running windows services. PowerShell did that for us internally!

PowerShell has its own internal mechanism to work with results in the pipeline and to process them and give us the next resultset that we can again send further down in pipeline as needed.

The only thing I can say is: “Thank you PowerShell for doing this for us”.

How PowerShell Pipeline Concept Works

So far we know that pipelining is linking the output objects from one command to another command. Let’s now explain how this linking mechanism works.

Basically what PowerShell tries to do is to associate the piped objects from the command’s result with one of the parameters of the receiving command.

Let’s see one example and how the linking mechanism works.

IMPORTANT: I do not recommend to run this code but rather look this as an illustration example.

Get-Service -Name "Bonjour Service" | Restart-Service

We need to do several things:

  • Look at which parameters of receiving CmdLet accept pipeline input and what each such parameter has as data type (Restart-Service CmdLet in this case).
  • What is the result’s object type of sending command (Get-Service CmdLet in this case)?

To find which parameters of receiving CmdLet accept pipeline input run following command (and look the value in Accept pipeline input? property):

Get-Help Restart-Service -Parameter *
Parameters of Restart-Service CmdLet that accept pipeline input

OR

Get-Help Restart-Service -Full

As we can see on the screenshot above we can find that only two parameters accept pipeline input:

  • InputObject parameter accepts pipeline input by Value and it is ServiceController data type.
  • The Name parameter accepts pipeline input both by Value and by Property name. The name parameter is String array data type (String[])

We will discuss Pipeline input by Value and by Property Name terms in a bit.

How we can find data type of resultset object(s) for Get-Service CmdLet. Well, use Get-Member CmdLet and run the following command and we will get the answer.

Get-Service | Get-Member
Get-Service CmdLet returns objects of ServiceController data type

Get-Service CmdLet returns objects of ServiceController data type.

So let’s put together all the pieces that we have found so far:

  • Get-Service returns as result objects of type ServiceController.
  • These objects of type ServiceController are sent down to the pipeline to the Restart-Service CmdLet (receiving CmdLet).
  • Restart-Service CmdLet has two parameters that accept pipeline input:
    • Name
    • InputObject
  • The Name parameter type is an array of Strings. The string array data type does not match the ServiceController data type so the link between the result of Get-Service CmdLet and parameter Name in Restart-Service CmdLet cannot be established so there is no pipeline associated with them.
  • However, the InputObject parameter data type is an array of ServiceController objects. So objects of Get-Service CmdLet result are ServiceController data type and the Parameter InputObject data type is ServiceController. That is a perfect match and link between two CmdLets in the pipeline.
  • CONCLUSION: ServiceController data type in Get-Service CmdLet resultset objects and ServiceController data type in InputObject parameter of receiving CmdLet Restart-Service is the pipeline link between two CmdLets.

INFO: This is the Pipeline ByValue method that I will further explain in the examples section accompanied by one more example of another pipelining method ByPropertyName.

Ways Of Accepting PowerShell Pipeline Input

Cmdlets parameters can accept pipeline input in one of two different ways:

  • ByValue: PowerShell will try to match the data type (or convert to matching data type) of objects sent to the pipeline with the data type of parameter that accepts input ByValue from the receiving command.
  • ByPropertyName: PowerShell will try to match the property of the object sent to the pipeline with the name of the parameter that accepts input ByPropertyName from the receiving command.

If the previous descriptions look complicate and non-understandable please bear with me and I will try to explain that with examples that follow.

Some parameters can accept objects by value or by property name. These parameters are designed to take input from the pipeline.

I will explain both methods in more detail with examples in the next section so I hope they will be crystal clear for you.

Examples Of Accepting PowerShell Pipeline Input

In these examples, I will use my own CmdLet Get-CPUInfo that is part of the Efficiency Booster PowerShell Project. This project is a library of many awesome CmdLets that help us to accomplish everyday IT tasks faster and more accurate without repeating the boring steps over and over again.

Please download the source code of CmdLet if you want to follow me along.

Get Processor CPU Information Using PowerShell Script
Get-CPUInfo CmdLet article

Example Of Accepting PowerShell Pipeline Input ByValue

If we run the following code we will get CPU properties for the local machine as we can see on the screenshot below:

'localhost' | Get-CPUInfo -client "OK" -solution "FIN" -errorlog
Pipeline Input ByValue resultset

How PowerShell Pipeline Input ByValue Method Works

PowerShell will look for the following things:

  • What is the data type of the objects sent to the pipeline? (sending side of the PowerShell pipeline, left from pipeline sign “|”)
  • On the receiving side of the PowerShell pipeline (right from pipeline sign “|”) PowerShell will look for two things:
    • Which Parameters of receiving PowerShell command accepts pipeline ByValue input and,
    • What is the data type of those parameter(s) that accept pipeline ByValue input?
  • Finally, PowerShell will try to match (or convert data type if needed and possible) data type of objects sent to the pipeline to the data type of one of the parameter(s) that accept input ByValue pipeline on the receiving side.

Now when we know how the PowerShell Pipeline Input ByValue method works let’s apply that on our example.

Step 1: Let’s look at the data type of objects sent to the PowerShell pipeline.

In order to find the data types of objects we will use Get-Member CmdLet running the following command:

'localhost' | Get-Member 
The data type of object(s) sent to the PowerShell Pipeline

Now we know that String data type object(s) has been sent to PowerShell Pipeline.

Step 2: Let’s find out which parameters of receiving PowerShell command (Get-CPUInfo CmdLet in this case) accepts pipeline input ByValue

We will use Get-Help CmdLet with Parameter and look in the (Accept pipeline input?) field value in order to find which parameters accept PowerShell pipeline input ByValue:

Get-Help Get-CPUInfo -Parameter *
computers parameter accepts Pipeline Input ByValue method

As you can see on the screenshot above only the computers parameter accepts PowerShell Pipeline Input ByValue method all the other parameters have false value for (Accept pipeline input?) field value as the result of calling Get-Help CmdLet.

Step 3: Let’s find out which data type accepts the parameter(s) that accepts the PowerShell Input ByValue method.

We will use Get-Help CmdLet with Parameter and look in data type for each parameter that accepts the Input ByValue pipeline method. For this example, it is easy since only the computers parameter accepts the pipeline input ByValue method.

Get-Help Get-CPUInfo -Parameter computers
The computers parameter accepts an array of strings data type as input

We have found that the computers parameter accepts an array of strings as input.

Step 4: Let’s try to match the data type of objects sent to the pipeline with the data type of parameter that accepts an input ByValue pipeline method.

In this example it is easy and no conversion of data type is needed since ‘localhost’ is a string value sent to the pipeline and “computers” parameter of Get-CPUInfo CmdLet accepts an array of strings as input ByValue in the pipeline which is a perfect match of datatypes.

Trace-Command CmdLet With Accept Pipeline Input ByValue Method

If we want to be really technical and see what PowerShell is doing while implementing Input ByValue Pipeline method we should use Trace-Command CmdLet like in the following example:

Trace-Command -Expression { 'localhost' | Get-CPUInfo -client "OK" -solution "FIN" -errorlog } -Name ParameterBinding -PSHost
Trace-Command CmdLet result and Input ByValue Pipeline method implementation

As you can see from the screenshot above PowerShell successfully bind the ‘localhost’ value sent into the pipeline with the computers parameter of Get-CPUInfo CmdLet.

Example Of Accepting PowerShell Pipeline Input ByPropertyName

If we run the following code we will get CPU properties for the local machine as we can see on the screenshot below:

'localhost' | Select-Object @{label="computers";expression={$_}} | Get-CPUInfo -client "OK" -solution "FIN" -errorlog

IMPORTANT: In this example, we will focus on pipeline between the second command and the last (third) command since there has been implemented PipeLine input ByPropertyName.

Pipeline Input ByPropertyName resultset

NOTE: We get the same resultset as in the previous example the only difference is the binding method of the pipeline. Here is used pipeline input ByPropertyName method instead.

How PowerShell Pipeline Input ByPropertyName Method Works

PowerShell will look for the following things:

  • What is the property name of the objects sent to the pipeline? (sending side of the PowerShell pipeline, left from pipeline sign “|”)
  • On the receiving side of the PowerShell pipeline (right from pipeline sign “|”) PowerShell will look for two things:
    • Which Parameters of receiving PowerShell command accepts pipeline ByPropertyName input and,
    • What are the names of parameters that accept pipeline input ByPropertyName?
  • Finally, PowerShell will try to match the property name of objects sent to the pipeline to the name of the parameter that accepts the input ByPropertyName method.

Now when we know how the PowerShell Pipeline Input ByPropertyName method works let’s apply that on our example.

Step 1: Let’s look at what the property name of objects sent to the pipeline is.

We will use Get-Member CmdLet with the MemberType parameter in order to find out the property name of objects sent to the pipeline.

'localhost' | Select-Object @{label="computers";expression={$_}} | Get-Member -MemberType Properties
Property name of the object(s) sent to the PowerShell Pipeline is computers

Now we know that the property name of the object(s) sent to the PowerShell Pipeline is computers.

Step 2: Let’s find out which parameters of receiving PowerShell command (Get-CPUInfo CmdLet in this case) accepts pipeline input ByPropertyName.

We will use Get-Help CmdLet with Parameter and look in the (Accept pipeline input?) field value in order to find which parameters accept PowerShell pipeline input ByPropertyName:

Get-Help Get-CPUInfo -Parameter *
computers parameter accepts Pipeline Input ByPropertyName method

As you can see on the screenshot above only the computers parameter accepts PowerShell Pipeline Input ByPropertyName method all the other parameters have false value for (Accept pipeline input?) field value as the result of calling Get-Help CmdLet.

Step 3: Let’s find out the name of the parameter(s) that accept pipeline input ByPropertyName.

In this example answer to that question is easy since we have already found out that this is a computers parameter.

Step 4: Let’s try to match the property name of the object(s) sent to the pipeline with the name of the parameter that accepts pipeline input ByPropertyName method.

So ‘localhost’ value sent to the pipeline has been labeled as ‘computers‘ which is a perfect match with the name of parameter ‘computers‘ of Get-CPUInfo CmdLet that accepts input ByPropertyName.

Trace-Command CmdLet With Accept Pipeline Input ByPropertyName Method

If we want to be really technical and see what PowerShell is doing while implementing Input ByPropertyName Pipeline method we should use Trace-Command CmdLet like in the following example:

Trace-Command -Expression {  'localhost' | Select-Object @{label="computers";expression={$_}} | Get-CPUInfo -client "OK" -solution "FIN" -errorlog } -Name ParameterBinding -PSHost
Trace-Command CmdLet result and Input ByPropertyName Pipeline method implementation

As you can see from the screenshot above PowerShell successfully bind the ‘localhost’ value sent into the pipeline and labeled as ‘computers‘ with the ‘computers‘ parameter of Get-CPUInfo CmdLet.

How To Write Parameters That Accept Pipeline Input In Own Functions

I have written the article How To Create PowerShell Parameters Step By Step which explains PowerShell Parameters with many examples and I would like to emphasize this section of that article that explains the code of ‘computers‘ parameter from Get-CPUInfo CmdLet that we have used as an example in this article.

So please read this article in order to learn how to write parameters that accept pipeline input when you write your own functions.

How To Create Parameters In PowerShell Step By Step
How To Create PowerShell Parameters Step By Step

How To Test Parameters That Accept Pipeline Input

We have done testing in this article but I have written an article dedicated to PowerShell Parameters How To Create Parameters In PowerShell where I have tested both Pipeline input methods:

Useful PowerShell Pipeline Articles

Here are some useful articles and resources:


Do you feel more like a plumber rather than a PowerShell script developer after reading so many times pipeline?

About Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals!
I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials
About Me...

My Posts | Website

Dejan Mladenović

Hey Everyone! I hope that this article you read today has taken you from a place of frustration to a place of joy coding! Please let me know of anything you need for Windows PowerShell in the comments below that can help you achieve your goals! I have 18+ years of experience in IT and you can check my Microsoft credentials. Transcript ID: 750479 and Access Code: DejanMladenovic
Credentials About Me...

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Recent Content