Pipeline in PowerShell
As a PFE, I travel quite a bit to different customer locations. Today, while sitting at the airport waiting to board my flight, I started wondering about the pipeline in PowerShell. If you think of it, the airplane could be correlated to a pipeline from which we humans and other objects (such as bags etc.) are passed from one place to another. Yeah, too much of PowerShell could do that to you.. you start seeing objects and pipeline everywhere! :)
On that thought, I decided to blog about pipeline in PowerShell while waiting to be "piped" from my current location to my destination!
There are a few aspects of pipeline which I'd like to discuss in this blog post. Firstly, what is passed through the pipeline and when can you use pipeline. To begin with, let's look into what passes through the pipeline...
Since this blog's scope is pipeline and not cmdlets, I am not going into detail of following cmdlets which I am using for demonstration - Get-Process, Foreach-Object, Start-Sleep and Import-CSV.
Let's start with one of the well-known cmdlets - Get-Process. Get-Process returns "process" objects, we can verify that by using Get-Process | Get-Member. The result will tell you that the cmdlet outputs
"Process" objects:
Now lets pipe this output into the foreach-object cmdlet:
Get-Process | Foreach-Object { $_ }
The output seems the same if compared with the output from Get-Process cmdlet:
Let's do some changes to the statement above to get a better understanding of what exactly is happening. Let’s add a delay of 1 second to the output by using Start-Sleep -seconds 1 cmdlet:
Get-Process | Foreach-Object { Start-Sleep -seconds 1; $_ }
This might give you a better view of the fact that objects are being passed through the pipeline and worked on asynchronously by the foreach-object cmdlet. However, you saw only ProcessName, WS, VM etc. in
the header of the output. Does that mean only these pieces of objects were passed through the pipeline? Certainly not, PowerShell is just displaying the specific properties of the "process" objects. We can confirm that by using Get-Member on our sequence of cmdlets:
Get-Process | Foreach-Object { $_ } | Get-Member
The above statement will display all the properties of the process object. If you compare, the output is similar to Get-Process | Get-Member. This demonstrates that entire process object is passed from the source
to destination cmdlet.
Now that we understand objects are passed through the pipeline, let’s move on to the next objective of this blog – ‘when can you use the pipeline’ .
Let’s take an example of Start-Service cmdlet and focus our attention on the "Name" parameter of the Start-Service cmdlet.
Let's do Get-Help Start-Service -Parameter Name to get only "Name" related help information.
Accept Pipeline Input - true - tells us that information can be piped into this parameter. We can see that there are two ways of passing these parameter values - "ByPropertyName" and "ByValue".
Let’s start with "By Value". As the name suggests, the value can be passed through the pipeline. That is, these two statements are equivalent..
Start-Service -Name bits
"bits" | Start-Service
where "bits" is the name of the service. Instead of passing value through the parameter, we passed the value through a pipeline as the parameter accepts pipeline input "by value". While piping, the datatype of the value was matched with the datatype of the parameter. The string datatype in this case matched with the datatype of the parameter “Name” and hence the statement was successful in starting the service named “bits”.
Now let’s look at other piece of the "Accepts Pipeline Input" - "By PropertyName". As the name suggests, we need to pass objects to the cmdlet and these objects should have property with the same name as the name of the parameter in the cmdlet. (This will be explained in the following example).
That is, in our example, we need to have an object with a property "name" (same as parameter "Name") to pass to the Start-Service cmdlet There are multiple ways of creating objects or properties in PowerShell, but that is outside the scope of this blog post.
Let’s use the Import-CSV cmdlet to create an object having property called "Name". For that, we will create a service.csv file with the following text:
name,description
bits,description of the service
Import-CSV on that file will give you the following output. An object has been created with "name" as one of its properties:
To make it simpler, lets use Get-Member to check the properties of the object. Lets do Import-CSV proc.csv | Get-Member -MemberType *Property to list all the properties of the object:
We can see that an object exists with "name" as one of its properties. Now, we will pass this object to Start-Service cmdlet.
Import-CSV service.csv | Start-Service
Once we do that, we will see that the "bits" service is started.
What happens behind the scenes is: the object generated from Import-CSV was passed to the Start-Service cmdlet. This object had a property called "name" which matched with the parameter called "Name" of Start-Service cmdlet. The property name had a value called "bits", therefore Start-Service started the "bits" service.
Hopefully, these examples should have given you a good understanding of the fundamentals of pipeline in PowerShell.
See you in my next topic of PowerShell. Till then, keep scripting! :)