Working with the PowerShell Pipeline
*If you're just joining us, this post is part of a 12-part series on Getting Started with PowerShell. If you'd like to catch up (or skip ahead - more posts coming soon), click on the appropriate post below.
Getting Started with PowerShell
Windows PowerShell, PowerShell Core and PowerShell: Huh?
Installing PowerShell and Visual Studio Code
Running PowerShell Commands and Getting Help
One of the most unique features of PowerShell is the pipeline. Unlike many other shells that pass simple strings from command to command, PowerShell passes rich objects. But what's a string and object and what does that have to do with a pipeline anyway? Stay tuned to find out!
Strings
In PowerShell and other programming languages, strings are everywhere. Strings are a specific type of data that represents one or more simple characters. In PowerShell, if you type some characters and surround them with single or double quotes, you've created a string.
PS> 'foo'
Strings are simple types that essentially only "contain" the characters you see. If you type 'foo'
in a PowerShell console, you'll notice it returns the word foo
. But, if you run a command like Get-Service
, you'll see a lot of information returned. One big difference is Get-Service
returns an object and not a simple string.
Objects
Objects are commonplace in software development work. Objects are logical representations of a "thing" with properties that describe it and methods that detail what actions it can do. This article will not be a tutorial on topics like object-oriented programming, but it is important to know the basics of what objects are and how to work with them at a rudimentary level.
Objects have properties and methods. As you are just starting out, don't worry about methods for now. You'll be working with properties a whole lot more.
An object property is an attribute. It's an item with a value that represents a particular trait of that object. For example, you can think of a car as an object. A car has various attributes like color, engine size, number of doors, etc. Each of those attributes could be a property of the car object.
A single object property can be a string. Think about that for a minute. An object could consist of hundreds of strings! Objects just contain a lot more data and information. This knowledge will come in handy when you learn about the PowerShell pipeline.
The PowerShell Pipeline
Whenever you run a command in PowerShell, it may return something. It may return a Windows service, a line in a text file or an Active Directory user. That thing the command returns is an object.
Sometimes, you'll need to use the output (object) from one command and use that as input to another command. One way to do that is with the pipeline.
Whenever you "pipe" one command's output to another command's input, that's know as the pipeline. You will "pipe" objects across the pipeline using the pipe symbol (|
).
For example, let's say you'd like to stop a running Windows service using the pipeline. PowerShell has a cmdlet called Stop-Service
that stops a Windows service. To stop a Windows service, you must tell the cmdlet what service to stop.
You have two ways to tell the Stop-Service
cmdlet the service to stop by either using the Name
or DisplayName
parameters or with the InputObject
parameter.
If you weren't using the pipeline, you could stop a service like this
Stop-Service -DisplayName 'Windows Update'
However, you can also give the service to the Stop-Service
cmdlet using the InputObject
parameter as well. The below method is more complex because the InputObject
parameter accepts a certain type of object. You can't use the string Windows Update
as a value for the InputObject
parameter.
Instead, you must generate an object which Get-Service
returns and pass that as the value for InputObject
.
Stop-Service -InputObject (Get-Service -DisplayName 'Windows Update')
Notice though, you're still not using the pipeline. We'll get there!
Rather than providing the object that Get-Service
returns to the InputObject
parameter like above, you can use the pipeline to send the object from Get-Service
directly to the Stop-Service
command.
Now notice below that you're not explicitly passing any parameters to Stop-Service
. The Stop-Service
cmdlet understands the input it's getting from Get-Service
. It knows that the object being sent to it is for the Windows Update service and stops it accordingly.
Get-Service -DisplayName 'Windows Update' | Stop-Service
Note that not all PowerShell cmdlets support input via the pipeline. To discover which cmdlets support pipeline input run Get-Help [cmdlet name] -Detailed. You can see below that the Get-Service InputObject parameter does, indeed, support pipeline input.
Taking it to the Next Level
The previous section was a simple example of using the pipeline. You didn't see a great use case that makes the pipeline so powerful. Let's change that.
Let's now say you have a lot of Windows services to start on a computer name stored in a text file, one per line, called services.txt. To do that, you'll first need to read that text file using the Get-Content
cmdlet. This cmdlet will return one service name per line.
Get-Content -Path 'C:\services.txt'
Next, you'll need to get the service objects to start. You can do this by sending all of the service names returned via Get-Content directly to Get-Service.
Get-Content -Path 'C:\services.txt' | Get-Service
Once you have the command to get all of the service objects, you can then add Start-Service to the end of the pipeline to start all of the services.
Get-Content -Path 'C:\services.txt' | Get-Service | Start-Service
You can continue adding commands for as long as you'd like. In one line, this command has:
Read each service name in the text file
Enumerated all service in the text file
Started all services found
Summary
The PowerShell pipeline is a great way to process one, ten or 100 objects at once with a limited amount of code. Due to the incoming cmdlet's intelligent pipeline-binding features, it knows how to read each object being passed through it.
Use the pipeline to not only cut down on code used but also as a way to quickly process many different objects at once.