Aug 25, 2016
I have been running the PowerShell Basics series of blogs for a while now, and in those blogs I have given a myriad of example commands, but so far I have neglected to detail what I think is one of PowerShell’s greatest feature, and that is its ability to “pipe” the output of one cmdlet into the input of the next cmdlet. Please allow me to rectify that situation now.
Now PowerShell is certainly not the first command-line shell to use the concept of a pipeline. Unix is usually credited with first using the concept back in the early 70’s, and it has been used in most other command-line shells since. But the big difference between all the other command-shell’s piping and PowerShell’s gets back to the core of what PowerShell is – namely PowerShell is an object oriented shell, so when the output of one cmdlet is “piped” into the input of the next cmdlet, it is an object that is passed along and not just a text string. And - if you will pardon the pun – this is just one feature that makes PowerShell so powerful, so flexible and so much more capable than previous shells, but yet so intuitively easy to understand as well. Take the following example command lines for example:
Get-Service | Out-File ServiceList.txt
Get-EventLog –LogName Security –Newest 5 | Out-GridView
We can see here that the first line is getting is getting the services currently on our PC, and the Out-File cmdlet is converting those service objects to a text string and then saving that text string as a file. The second line is getting the contents of the eventlog called security,filtered down to just the latest 5 entries and then showing the results in a separate dialog box. Simple logical progression right? Now if the output of the GetService or the Get-Eventlog cmdlets was in plain text, then we would have had to include lots of other commands to find the exact location of the text fields we wanted in the output, cull to just the fields we needed and then have to exactly specify how and where to send that output. PowerShell is able to intuitively take a lot of those pedantic operations on our behalf and simplify them. Try doing those simple operations in a text based only command-line shell and you will quickly see what I mean!
OK, so lets start with the basics – the Windows PowerShell Pipeline is a technique where PowerShell runs multiple commands in a sequence of cmdlets from left to right, where the output of one cmdlet is used as the input for the next cmdlet. Each cmdlet is separated by the vertical pipe (|) character (ASCII 124 – on a typical US keyboard layout this is usually the symbol above the (\) character on the key above the ENTER key). This is a very efficient way of allowing you to put a related sequence of cmdlets on the same line and results in both a clearer understanding of the task sequence, and reduced code complexity. Note that if you wish to type a single logical command line over multiple physical lines, you can use the backtick or grave character (`) (ASCII 96) as in Get-Service` and press ENTER. If you use this when manually typing in the PowerShell console, it will then return with >> indicating you need to complete the command line. Pressing CTR-C will “break” out of this extended command mode if required. By the way, in my examples I generally put a space before and after the pipe character, primarily for readability, but in actual fact the spaces are optional.
Now most PowerShell cmdlets produce their output as objects, which makes it very easy to filter, order, sort, count, measure, and construct various loops etc. based upon a property or properties of that object, and I have given a number of examples in previous blogs (see PowerShell Basics – Measuring Objects and PowerShell Basics – Manipulating Strings; -If “file_x” exists; Date and Time Manipulations; More PowerShell Constructs and Loop Manipulations etc. etc.). Don’t forget you can use the Get-Member cmdlet to view the Properties and Methods of the object(s) being output, as in:
Get-Service | Get-Member
You can think of these objects as lines in a spreadsheet – the rows are each unique object, the columns are the properties of that object and the cell contents are the particular value(s) of that object’s properties. Which means that when we want to reference a particular property we simply name that property in our subsequent cmdlets eg:
Get-Service | Format-Table Name, Status
That command sequence simply gets all of the services currently on the local PC, filters the object output to just the Name and Status properties, and displays those properties on the screen – which brings me to my next point.
I did say above that most PowerShell cmdlets give their outputs as objects, and that is true, but that is far from everything that PowerShell can do as far as cmdlet outputs. There are also a number of cmdlets that produce other kinds of outputs, such as a text string (e.g Format-Table and Out-String); HTML (e.g. ConvertTo-HTML); XML (e.g. Export-Clixml). Some cmdlets that give a boolean result (True or False, such as Test-Path) or redirect the output to some other medium (e.g. Out-File and Out-Printer). Other cmdlets can produce multiple kinds of objects in their output – such as Get-Childitem (which can produce both FileInfo and DirectoryInfo object types), and even cmdlets such as Compare-Object (which compares two objects or collections and marks their differences), or Tee-Object (which saves the output into a file or variable AND also passes the output on to subsequent cmdlets).
As a general rule, because these types of cmdlets are producing a different kind of output, they should be placed at the end of our pipeline sequence of cmdlets (with the possible exception of Tee-Object !). In fact PowerShell again helps us out here as well. Try these simple cmdlets:
Dir | Out-Default
Both outputs are the same right? That is because PowerShell is automatically and internally appending the Out-Default cmdlet, which converts the output to text, and then displays it on the console (the default here is the PowerShell console). Of course you can override that default by specifying your own cmdlet such as Out-File. So even if you just type in a single PowerShell cmdlet, you are still using the PowerShell pipeline technique without even knowing it!
So, that in a quick nutshell that is the PowerShell Pipeline, but if you want more information have a look at the PowerShell courses available from New Horizons, the 10961 - Automating Administration with Windows PowerShell, or the 10962 - Advanced Automated Administration with Windows PowerShell, and have fun trying some the examples and cmdlets I have mentioned above!