Nmedia - Fotolia

Tip

Start using the PowerShell pipeline with this example

An administrator can create functions to support the PowerShell pipeline, which improves upon text-based shells by allowing the scripter to pass objects across the pipe.

One of the language constructs that makes Windows PowerShell unique is the pipeline.

Although the pipeline was long a staple of various shells, PowerShell improved upon the traditional concept by allowing the scripter to pass objects across it rather than simple text strings. PowerShell provides hundreds of cmdlets built to support the pipeline. By creating custom functions in a particular way, you can create commands that support the PowerShell pipeline.

Once you see these examples of the pipeline in action, you'll learn how to incorporate PowerShell pipeline constructs into your functions.

In the legacy Windows command prompt, the concept of a pipeline entailed taking STDOUT output and piping it directly into STDIN input. A typical piping scenario is if you needed to get a file listing from a folder with many files and need to page through them. The paging function is performed by the more command. The more command accepts pipeline input, so if I'd like to get a file listing one page at a time, I could send the output of dir directly to more: dir C:\ | more.

Not all commands support input in this manner, and Microsoft did not design the command prompt to do much more than this, unlike PowerShell. PowerShell has native support for pipelining. For example, perhaps you'd like to get all running processes on a computer. You can use the Get-Process cmdlet by itself (see Figure 1).

PowerShell Get-Process output.
Figure 1. This result comes from the Get-Process cmdlet in PowerShell.

To just see the process name, you can pipe the output of Get-Process directly to another command; Select-Object (see Figure 2). You can continue this process ad infinitum with PowerShell pipelines (see Figure 3).

Select-Object with Get-Process in PowerShell.
Figure 2. With a PowerShell pipeline, the user can view just process names from the Get-Process output.

File collecting Get-Process with Select-Object in PowerShell.
Figure 3. The output from Get-Process with Select-Object is piped directly into a file, displaying the first ten lines of content.

With additional effort, a PowerShell pipeline can go beyond these built-in commands to include custom functions built in PowerShell. The administrator must use a couple of parameter attributes called ValueFromPipeline and ValueFromPipelineByPropertyName. These two attributes attached to various parameters in your function allow it to take input directly from the pipeline and use the parameter values inside of the function. Although similar, each attribute behaves a little differently.

By creating custom functions in a particular way, you can create commands that support the PowerShell pipeline.

With the ValueFromPipeline attribute, we can use the Get-Process example again, extending it to a custom-built function that takes the process objects that Get-Process outputs as input.

A simple advanced function might look like this:

function Test-Process

{

                [CmdletBinding()]

                param

                (

                                [Parameter()]

                                [string]$ProcessName

                )

               

                if ((Get-Process -Name $ProcessName).Responding -eq $True)

                {

                                $true

                }

                else

                {

                                $false             

                }

}

This function allows the system to specify a process by its name, test for a given property, and return $true or $false. It works, but duplicates effort because of the way it is presented. Another method would be to use the function to run for every process on your computer:

Get-Process | ForEach-Object {Test-Process –ProcessName $_.Name}

This still isn't very efficient. You're running Get-Process twice for every object. It'd be much better to simply send the output of Get-Process directly to Test-Process without having to use ForEach-Object.

Instead let's build a function to support PowerShell pipeline input by accepting each object that Get-Process outputs. An example of this custom-built function follows:

function Test-Process

{

                [CmdletBinding()]

                param

                (

                                [Parameter(ValueFromPipeline)]

                                [System.Diagnostics.Process]$Process

                )

                process

                {

                                if ($Process.Responding -eq $True)

                                {

                                                $true

                                }

                                else

                                {

                                                $false

                                }

                }

}

Finally, directly pipe the output of Get-Process into Test-Process: Get-Process | Test-Process.

There are a few distinct changes. First, the ValueFromPipeline parameter attribute goes inside of the parameter declaration parenthesis. This tells PowerShell to look at whole objects coming in from the pipeline and attempt to match each object to this parameter. Next, the type changes from string to System.Diagnostics.Process. This change lets the parameter type match the output object type of Get-Process so the command executes successfully.

Figure 4 shows how to use Get-Member to find the type of object that Get-Process outputs.

PowerShell using Get-Process and Get-Member
Figure 4. In a PowerShell pipeline, Get-Member finds the type of object output by Get-Process.

To process each object coming in from the PowerShell pipeline, the function must include a process block. Without a process block script, the function would stop after processing the first object.

And finally, because the command accepts the entire System.Diagnostics.Process object instead of just the process name, it makes all of the properties available. The PowerShell user can simply read the responding property's value from the $Process parameter without having to call Get-Process again.

There are more in-depth tips available from experts such as Boe Prox on pipeline support that will help you to build functions to use the ValueFromPipeline parameter attribute and also the ValueFromPipelineByPropertyName attribute.

Next Steps

Use PowerShell on remote servers

Considering an upgrade to PowerShell 5? Read this

How to manage multiple servers from PowerShell

What's wrong with your script? Check out automatic variables

Dig Deeper on Microsoft identity and access management

Cloud Computing
Enterprise Desktop
Virtual Desktop
Close