Working with the PowerShell Pipeline

This entry is part 3 of 9 in the series Learn PowerShell

The PowerShell Pipeline

Of all the concepts you’ll learn in this series, the PowerShell pipeline is arguably the most important.

Lets start with a simple definition. A pipeline combines commands connected by pipeline operators. Unlike many other shells, PowerShell is not limited to passing only strings along the pipeline. Complex objects can be passed from one command to the next making PowerShell very powerful!

PowerShell Pipeline Operator

In PowerShell, the pipeline operator is: |

PowerShell Pipeline Operator
# In this example, every command found will be "piped" to Get-Help
# This will run Get-Help against EVERY command found
Get-Command | Get-Help

This operator sends the results of the preceding command to the next command. In the above example, Get-Help will return help for every command discovered by Get-Command. If 1,000 commands are found on your device, this command would find help for all 1,000 of them!

Video

If you prefer video format over written documentation I discuss this topic in the following TechThoughts video:

Using the PowerShell Pipeline

You can leverage the pipeline to perform powerful actions in your environment, as well as work with objects.

Pipeline Passing

You can pass the results of one cmdlet to another to take various actions:

# This example would restart the BITS service!
Get-Service -Name BITS | Restart-Service

Look at another example below. Without the use of the WhatIf parameter, what action do you think would result?

# try running this command on your machine to see the results.
# the WhatIf parameter will make Stop-Process take no actual action
Get-Process | Stop-Process -WhatIf

If you were to remove the WhatIf parameter in the above example, PowerShell would immediately Get, and start stopping all the processes on your device. As you can imagine, that would lead to some pretty undesirable outcomes, likely resulting in your device crashing.

This is a good time to mention that PowerShell doesn’t contain a lot of hand holding. Its a tool that respects that you have an operational understanding of the commands that you run.

PSItem

When working with the PowerShell pipeline there is one automatic variable that is of particular importance, $PSItem. $PSItem contains the current object in the pipeline.

If you are new to PowerShell, this may seem like an abstract concept, but all that PSItem is doing is “holding” the current object in the pipeline. Lets take a look at an example:

# Get all processes. For each process (object) found, display that object
Get-Process | ForEach-Object {$PSItem}

The above example gathers all processes, and then for each process discovered, outputs that object to the console window. This works because $PSItem contains the current object in the pipeline. Lets see this in action again:

# In this simple example, we will display the current object to the console
1,2,3 | ForEach-Object {$PSItem}

Again, we see that $PSItem contains the current object. We loaded three simple numbers into the pipeline: 1,2,3. For each of these “objects” we returned the current object in the pipeline using $PSItem.

$PSItem is rarely fully spelled out in day-to-day PowerShell. Instead, utilize the shorthand $_ to denote the current pipeline object. $_ and $PSItem are one and the same. Try it yourself:

# Spelling out $PSItem (not common)
1,2,3 | ForEach-Object {$PSItem}
# using $PSItem shorthand (common)
1,2,3 | ForEach-Object {$_}
PowerShell PSItem $PSItem current pipeline object

Processing data with the pipeline

As previously mentioned, many cmdlets will return a predefined subset of information that you are most likely interested in. Many times though, you’ll be after all, or very specific object data that the cmdlet returns. Using the pipeline you can format, sort, and select the properties you want to work with.

Format-List & Format-Table

Format-List and Format-Table alter the output view of an objects properties. Try the following example:

# Note the way things look using Format-Table
Get-Process | Format-Table
# Now see how that differs if you pipe instead to Format-List
Get-Process | Format-List

Format-List can be used to see more properties of an object, rather than just a predefined subset of properties.

# Note the return from just Get-Date
Get-Date
# Now see how the whole object is returned if you pipe to Format-List
Get-Date | Format-List

With some cmdlets, especially those with a lot of data in the object, even Format-List will only return a portion of the object. Include an asterisk to ensure all data from the object is displayed:

# basic information about the notepad process
Get-Process notepad
# more information about the notepad process
Get-Process notepad | Format-List
# all available information about the notepad process
Get-Process notepad | Format-List *

Select-Object

On the flip-side you may find yourself wanting only a very specific set of properties from an object. Select-Object can help you achieve this. For instance, Get-Process returns detailed information about the running processes on a device. But what if you are only interested in a few of those key properties? Try the following:

# Using Select-Object you can retrieve only the properties you are after
Get-Process | Select-Object Name,Id,CPU,Responding

Sort-Object

You can take even further control over output using Sort-Object. Lets extend the previous example by sorting the output by the busiest processes. Try the following:

# This example pipes all processes to Sort-Object which sorts by CPU use
# Use to quickly identify your busiest processes. Very handy!
Get-Process | Sort-Object CPU

# You can combine multiple pipelines together as well
Get-Process | Select-Object Name,Id,CPU,Responding | Sort-Object CPU

Where-Object

Where-Object is one of the most powerful tools in your PowerShell toolbox. It operates a bit like Select-Object but has the added benefit of only selecting objects based on values you specify. This enables you to focus in and quickly identify specific results.

Where-Object will leverage the PSItem previously discussed to evaluate each object for the criteria specified. Lets start with an example where we only want to retrieve processes that are actively using the CPU:

# Get Processes, return only those where current object $_ is greater than 15
Get-Process | Where-Object {$_.CPU -gt 15}

Remember that $_ is the current object, which represents in this case, one full process object. However, we are only after objects where the CPU is greater than 15, so we are evaluating only the CPU property of the process object by specifying $_.CPU

Lets take a look at another useful example of Where-Object:

# Get file information for all files found in the $HOME directory
# Return information for only files that are greater than 5MB in size
Get-ChildItem $HOME -Recurse | Where-Object {$_.Length -gt 5MB}

There may seem like there is a lot going on here, so lets break it down:

Get-ChildItem $HOME -Recurse
This gets all files in your home directory

Where-Object {$_.Length -gt 5MB}
Using Where-Object we can evaluate only the Length property. The Length property is the size of the file. We only return information for files greater than 5MB

Using the power of the pipeline, you can even simply count how many large files you have. Try this example:

# Count the number of large file in your $HOME directory
Get-ChildItem $HOME -Recurse | Where-Object {$_.Length -gt 50MB} | Measure-Object

PowerShell Comparison Operators

Note that we used a comparison operator in the above examples (greater than). Comparison operators are a common component in all programming languages. Here are several common PowerShell comparison operators:

-eq       equals
-ne       not equals
-gt       greater than
-ge       greater than or equal to
-lt       less than
-le       less than or equal to
-like     wild card pattern match
-notlike  wild card pattern match 

PowerShell Parameters

So far in the series we’ve had a few examples where we’ve used parameters. Parameters in PowerShell are simply attributes of a cmdlet where you can specify various options or arguments.

Each cmdlet differs in the number and type of parameters they have. Some cmdlets have no parameters, while others have mandatory parameters. You can always use Get-Help to determine what parameters are available to a cmdlet.

# This standard cmdlet returns time zone information of the device
Get-TimeZone
# The ListAvailable parameter completely changes the behavior of this cmdlet
# Now, it lists the AVAILABLE timezones the device could be set to
Get-TimeZone -ListAvailable

Wrapping up the PowerShell Pipeline

The pipeline is what makes PowerShell so powerful. Many shells are limited to piping only strings. PowerShell is capable of passing entire objects of data between cmdlets. This ability to easily pass complex objects opens up a lot of possibilities. It enables you to perform various actions, or evaluate specific criteria in your environment quickly, easily, and accurately.

One thing to note is that you can’t just arbitrarily pipe objects around. For example Get-Service | Stop-Process wouldn’t work because Stop-Process is expecting a process object, not a service object.

Also keep in mind that not all cmdlets support pipeline input. You can always leverage Get-Help to determine what cmdlets support pipeline input.

The PowerShell pipeline is a critical component to master on your PowerShell journey. Feel free to comment below if you have questions on this topic!

Series Navigation<< Learn and use PowerShell with just three commandsPowerShell History and Current State >>

2 Responses

  1. Marty Hastings says:

    i do not have any programming skills. i have always said i would like to learn one. i would think, like everything else the more you use it the better you get at it. the problem comes (with me) when you don’t know what you want your program to do ……you cannot create one to do it. so….. practice?? i will continue to follow your PowerShell videos. I do want to learn.

    • I’m also learning programming. I think you are right @Marty Hastings. The more you use it the better you get at it. Right now, I’m just spending time learning the fundamentals until I build up more experience to start making programs.

Leave a Reply

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