DevOps | Scripts | Automation

Powershell

Pipeline functionality in PowerShell

PowerShell has the Pipeline structure support and that makes PowerShell more flexible, easy to use and easy to parse the output of the one command to the Next command as the Input.

Pipeline Structure:

As shown in the above diagram Command-A output is passed to the Command-B as the input. For example, Get-Service -Name Spooler command output is passed as the input to the Stop-Service.

Get-Service -Name Spooler | Stop-Service

Even a single command output in PowerShell uses a Pipeline. If we write the command only Get-Service, its output is also passed to the Pipelines as shown in the below code.

Get-Service | Out-Default | Out-Host
Pipeline Function:

So how does the actual Pipeline works in PowerShell? What exactly we can pass as input to the next command? We can’t pass any random things. For example, We can’t pass the process IDs to stop the services.

There are certain rules that the pipeline structure follows. The command which is accepting other commands output accepts two types of inputs.

  • ValueFromPipeline
  • ValueFromPipelineByPropertyName

ValueFromPipeline:

This property you can get using the Get-Help or Get-Command for the particular cmdlet. Consider the below example,

PS C:\> "Spooler" | Stop-Service -PassThru -Verbose
VERBOSE: Performing the operation "Stop-Service" on target "Print Spooler (Spooler)".

Status   Name               DisplayName
------   ----               -----------
Stopped  Spooler            Print Spooler

Here we are passing the Service name Spooler to the Stop-Service command. Let’s check the Stop-Service ValueFromPipeline property.

(Get-Command Stop-Service).ParameterSets.parameters

The above command retrieves the properties of all the parameters. We are just interested in the ValueFromPipeline Property. So we will filter it out.

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

Output:

Stop-Service accepts the two types of objects as input. One is InputObject and its Parameter type is ServiceController array. The second is Name and its parameter type is a String array.

We will first check the Name Property. It accepts the string array value of Service names.

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

Status   Name               DisplayName
------   ----               -----------
Stopped  Spooler            Print Spooler
Stopped  Winrm              Windows Remote Management (WS-Management)

Second is InputObject which accepts the ServiceController[]. To get the ServiceController type, we will use the Get-Service command and check its members using Get-Member.

You can see in the above image that Get-Service has the type ServiceController and it is for the single instance of the service, while the Stop-Service command accepts the array of the ServiceController means we can pass the multiple services. Ideally, the below example should work as per the above definition because we are passing an entire array of the ServiceController type which Stop-Service accepts.

Get-Service | Stop-Service 

If you are unsure what kind of consequences would occur after running the command, use the -WhatIf parameter to get the command predicted operation as shown below.

Get-Service | Stop-Service -WhatIf

ValueFromPipelineByPropertyName:

Another useful property of the pipeline is ValueFromPipelineByPropertyName. To get which command parameters support the Pipeline Property, we will filter the command like as shown in the first property,

(Get-Command Stop-Service).ParameterSets.parameters | where{$_.ValueFromPipelineByPropertyName -eq $true} | Select Name, ParameterType

Output:

So the Stop-Service accepts Name Property (string array[]) as the input. Get-Service command which also has the Name property and that is the reason Stop-Service accepts the Get-Service Name property.

Example is shown below,

Get-Service -Name Spooler, Winrm | Stop-Service -PassThru

Let’s take another example : Stop-Process,

(Get-Command Stop-Process).ParameterSets.parameters | where{$_.ValueFromPipelineByPropertyName -eq $true} | Select Name, ParameterType

Output:

Stop-Process command accepts two ValueFromPipelineByPropertyName parameters. Name and ID and we can use Get-process commands which have both properties supported to retrieve the value and pass it to the next command.

Get-Process -Name notepad, powershell | Stop-Process -PassThru
Get-Process -ID 12234,3433 | Stop-Process -PassThru

This is how the above two properties are the cornerstone for the Pipeline Structure. We can create a small script from the above commands to include both properties and you can also create a module for the same, if you don’t want to execute the script every time and function should be readily available.

(Get-Command Stop-Process).ParameterSets.parameters | where{($_.ValueFromPipelineByPropertyName -eq $true) -or ($_.ValueFromPipeline -eq $true)} | Select Name, ParameterType

Output:

You can also create a function as shown below and store it to .psm1 file to create a module and store it to the PowerShell Profile path to available for other users.

function Check-PipeLineProperty{
   param(
      [Parameter(Mandatory=$true)]
      [string[]]$commands
   )

   try{

       foreach($C in $commands){
    
     Write-Output          "`n******************************************************************************************`n"
     Write-Output "`n$c Pipeline Properties`n"

       (Get-Command $C).ParameterSets.parameters | `
       Where {($_.ValuefromPipeline -eq 'True') -or ($_.ValueFromPipelineByPropertyName -eq 'True')} | `
       Select Name,ParameterType, IsMandatory,ValueFromPipeline,ValueFromPipelineByPropertyName | Sort-Object ValueFromPipeline -Descending | ft -AutoSize   
    }
   }

   catch{
      Write-Host $_.Exception.Message -BackgroundColor DarkRed
   }

   

}

Output:

Download the .psm1 module from the GitHub location below.

https://github.com/chiragce17/CheckPipelineProperties