24/7/365 Support

Write Pipeline-Oriented Scripts with Cmdlet Keywords

Problem

Your script, function, or script block primarily takes input from the pipeline, and you want to write it in a way that makes this intention both easy to implement and easy to read.

Solution

To cleanly separate your script into regions that deal with the initialization, perrecord processing, and cleanup portions, use the begin, process, and end keywords, respectively.

Example 108. A pipelineoriented script that uses cmdlet keywords

function InputCounter

{ begin {

$count = 0 }

## Go through each element in the pipeline, and add up ## how many elements there were. process {

WriteDebug "Processing element $_" $count++ }

end { $count } }

This produces the following output:

PS >$debugPreference = "Continue" PS >dir | InputCounter DEBUG: Processing element CompareProperty.ps1 DEBUG: Processing element ConnectWebService.ps1 DEBUG: Processing element ConvertTextObject.ps1 DEBUG: Processing element ConvertFromFahrenheitWithFunction.ps1 DEBUG: Processing element ConvertFromFahrenheitWithLibrary.ps1 DEBUG: Processing element ConvertFromFahrenheitWithoutFunction.ps1 DEBUG: Processing element GetAliasSuggestion.ps1 (...) DEBUG: Processing element SelectFilteredObject.ps1 DEBUG: Processing element SetConsoleProperties.ps1 20

Discussion

If your script, function, or script block deals primarily with input from the pipeline, the begin, process, and end keywords let you express your solution most clearly. Readers of your script (including you!) can easily see which portions of your script deal with initialization, perrecord processing, and cleanup. In addition, separating your code into these blocks lets your script to consume elements from the pipeline as soon as the previous script produces them.

Take, for example, the GetInputWithForeach and GetInputWithKeyword functions shown in Example 109. The first visits each element in the pipeline with a foreach statement over its input, while the second uses the begin, process, and end keywords.

Example 109. Two functions that take different approaches to processing pipeline input

## Process each element in the pipeline, using a ## foreach statement to visit each element in $input function GetInputWithForeach($identifier) {

WriteHost "Beginning InputWithForeach (ID: $identifier)"

foreach($element in $input)

{ WriteHost "Processing element $element (ID: $identifier)" $element

}

WriteHost "Ending InputWithForeach (ID: $identifier)" }

## Process each element in the pipeline, using the ## cmdletstyle keywords to visit each element in $input function GetInputWithKeyword($identifier) {

begin { WriteHost "Beginning InputWithKeyword (ID: $identifier)" }

process

{ WriteHost "Processing element $_ (ID: $identifier)" $_

}

end { WriteHost "Ending InputWithKeyword (ID: $identifier)" } }

Both of these functions act the same when run individually, but the difference becomes clear when we combine them with other scripts or functions that take pipeline input. When a script uses the $input variable, it must wait until the previous script finishes producing output before it can start. If the previous script takes a long time to produce all its records (for example, a large directory listing), then your user must wait until the entire directory listing completes to see any results, rather than seeing results for each item as the script generates it.

If a script, function, or script block uses the cmdletstyle keywords, it must place all its code (aside from comments or its param statement if it uses one) inside one of the three blocks. If your code needs to define

and initialize variables or define functions, place them in the begin block. Unlike most blocks of code contained within curly braces, the code in the begin, process, and end blocks has access to variables and functions defined within the blocks before it.

When we chain together two scripts that process their input with the begin, process, and end keywords, the second script gets to process input as soon as the first script produces it.

PS >1,2,3 | GetInputWithKeyword 1 | GetInputWithKeyword 2 Beginning InputWithKeyword (ID: 1) Beginning InputWithKeyword (ID: 2) Processing element 1 (ID: 1) Processing element 1 (ID: 2) 1 Processing element 2 (ID: 1) Processing element 2 (ID: 2) 2 Processing element 3 (ID: 1) Processing element 3 (ID: 2) 3 Ending InputWithKeyword (ID: 1) Ending InputWithKeyword (ID: 2)

When we chain together two scripts that process their input with the $input variable, the second script can’t start until the first completes.

PS >1,2,3 | GetInputWithForeach 1 | GetInputWithForeach 2 Beginning InputWithForeach (ID: 1) Processing element 1 (ID: 1) Processing element 2 (ID: 1) Processing element 3 (ID: 1) Ending InputWithForeach (ID: 1) Beginning InputWithForeach (ID: 2) Processing element 1 (ID: 2) 1 Processing element 2 (ID: 2) 2 Processing element 3 (ID: 2) 3 Ending InputWithForeach (ID: 2)

When the first script uses the cmdletstyle keywords, and the second scripts uses the $input variable, the second script can’t start until the first completes.

PS >1,2,3 | GetInputWithKeyword 1 | GetInputWithForeach 2 Beginning InputWithKeyword (ID: 1) Processing element 1 (ID: 1) Processing element 2 (ID: 1) Processing element 3 (ID: 1)

Ending InputWithKeyword (ID: 1) Beginning InputWithForeach (ID: 2) Processing element 1 (ID: 2) 1 Processing element 2 (ID: 2) 2 Processing element 3 (ID: 2) 3 Ending InputWithForeach (ID: 2)

When the first script uses the $input variable and the second script uses the cmdletstyle keywords, the second script gets to process input as soon as the first script produces it.

PS >1,2,3 | GetInputWithForeach 1 | GetInputWithKeyword 2 Beginning InputWithKeyword (ID: 2) Beginning InputWithForeach (ID: 1) Processing element 1 (ID: 1) Processing element 1 (ID: 2) 1 Processing element 2 (ID: 1) Processing element 2 (ID: 2) 2 Processing element 3 (ID: 1) Processing element 3 (ID: 2) 3 Ending InputWithForeach (ID: 1) Ending InputWithKeyword (ID: 2)

Help Category:

Get Windows Dedicated Server

Only reading will not help you, you have to practice it! So get it now.

Processor RAM Storage Server Detail
Intel Atom C2350 1.7 GHz 2c/2t 4 GB DDR3 1× 1 TB (HDD SATA) Configure Server
Intel Atom C2350 1.7 GHz 2c/2t 4 GB DDR3 1× 128 GB (SSD SATA) Configure Server
Intel Atom C2750 2.4 GHz 8c/8t 8 GB DDR3 1× 1 TB (HDD SATA) Configure Server
Intel Xeon E3-1230 v2 3.3 GHz 4c/8t 16 GB DDR3 1× 256 GB (SSD SATA) Configure Server
Intel Atom C2350 1.7 GHz 2c/2t 4 GB DDR3 1× 250 GB (SSD SATA) Configure Server

What Our Clients Say