How does PowerShell Pipeline work – Part 1?

PowerShellMicrosoft TechnologiesSoftware & Coding

PowerShell is made easier with the Pipeline structure. With the Pipeline structure, we can pass the input of the left side command output or string to the right side of the command as the input. For example,

Get-Service | Out-File c:\services.txt

In the above example, we are passing Get-Service output as an object to the Out-File command which is the right side of the Pipeline as the Input. Before going into detail about how the Pipeline works, we need to understand that every command we write produces output and that output is already formatted by the PowerShell using Pipeline.

For example, Get-Process command, if we don’t format this command then the actual default command is,

Get-Process | Out-Default | Out-Host

Out-Default and Out-Host are invisible but actually works in the background. Out-Default sets the default format while the Out-Host command to print the output on the console.

In the Pipeline structure, the right side of the command is taking input from the left side of the output. So we need to understand, what exactly we can pass to the Pipeline, we can’t pass the random things like the name of the process or PID as the Pipeline as shown below.

"PowerShell" | Get-Process

"1002" | Get-Process

The above command will generate an error saying that the above command doesn't take the provided input as the pipeline input.

Get-Process: The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input
and its properties do not match any of the parameters that take pipeline input.

While for the Get-Service we can pass the names.

PS C:\> "Winrm","Spooler" | Get-Service

Status    Name     DisplayName
------    ----     -----------
Running   Winrm    Windows Remote Management (WS-Managem…
Running   Spooler  Print Spooler

Here the explanation is given below. To check what exactly we can pass as the input to the right side of the command, we need to use the Get-Command with the property name ParameterSet. You can also use the Get-Help command.

(Get-Command Get-Service).ParameterSets.Parameters

Once you run the above command, notice the two properties, ValueFromPipeLine and ValueFromPipelineByPropertyName, and check the True value. Let's filter out those properties.

In this article, we are covering the ValueFromPipleLine property. The valueFromPipelineByPropertyName parameter is covered in the next article (part-2).

(Get-Command Get-Service).ParameterSets.parameters | where{$_.ValueFromPipeline -eq 'True'} | Select Name,ParameterType


Name ParameterType
---- -------------
Name System.String[]
InputObject System.ServiceProcess.ServiceController[]

From the above output, we can pass Name as the Input object and its type is String[]. This means we can pass multiple service names and the same was discussed in the earlier example.

PS C:\> "Winrm","Spooler" | Get-Service

Status Name DisplayName
------ ---- -----------
Running Winrm Windows Remote Management (WS-Managem…
Running Spooler Print Spooler

Second is InputObject and its type is ServiceController[]. This is the type you can see when you use Get-Member of the command and in the first line, you will get the TypeName.

PS C:\> Get-Service | Get-Member
TypeName: System.Service.ServiceController

Let's take another example of the Stop-Service command to understand it better,

(Get-Command Stop-Service).ParameterSets.parameters | where{$_.ValueFromPipeline -eq 'True'} | Select Name,ParameterType
Name ParameterType
---- -------------
InputObject System.Diagnostics.Process[]

So the Stop-Process command only accepts the Process array as the input and if you check the Get-Process, its member type is also System.Diagnostics.process. Means we can pass the whole Get-Process as an input to the Stop-Process using a pipeline.

PS C:\> Get-Process | gm

TypeName: System.Diagnostics.Process

Get-Process | Stop-Process

This means if we pass the name of the process or Process ID then it shouldn’t work.

PS C:\> "2916" | Stop-Process
InvalidArgument: (2916:String) [Stop-Process], ParameterBindingException

PS C:\> "Notepad" | Stop-Process
InvalidArgument: (Notepad:String) [Stop-Process], ParameterBindingException

In the above example passing Process ID or Name of the process didn’t work because Pipeline doesn’t accept that input.

Published on 16-Oct-2020 13:13:06