In this part of our series, we look at the [Parameter()] attribute and how it enables parameters to receive pipeline input.
Receiving Pipeline Input
Without the [Parameter()] attribute, receiving pipeline input is cumbersome and inconsistent. You end up managing two separate variables depending on whether the input comes from arguments or the pipeline:
function Test-Me
{
process
{
"Received via pipeline: $_"
}
end
{
"Received via direct argument: $args"
}
}
PS> Test-Me 1
Received via pipeline:
Received via direct argument: 1
PS> 1..3 | Test-Me
Received via pipeline: 1
Received via pipeline: 2
Received via pipeline: 3
Received via direct argument:
Named parameters (as covered in Part 2) fail for pipeline input:
function Test-Me
{
param
(
$MyInputData
)
process
{
"Received via pipeline: $MyInputData"
}
end
{
"Received via direct argument: $MyInputData"
}
}
PS> Test-Me 1
Received via pipeline: 1
Received via direct argument: 1
PS> 1..3 | Test-Me
Received via pipeline:
Received via pipeline:
Received via pipeline:
Received via direct argument:
Binding Pipeline Input
To make named parameters work with pipeline input, you must tell PowerShell which ones can receive it. Decorate the parameter intended to handle pipeline input with the [Parameter(ValueFromPipeline)] attribute:
function Test-Me
{
param
(
[Parameter(ValueFromPipeline)]
$MyInputData
)
process
{
"Received via pipeline: $MyInputData"
}
end
{
"Received via direct argument: $MyInputData"
}
}
PS> Test-Me 1
Received via pipeline: 1
Received via direct argument: 1
PS> 1..3 | Test-Me
Received via pipeline: 1
Received via pipeline: 2
Received via pipeline: 3
Received via direct argument: 3
Remember: pipeline input must be handled in the process block. In the begin block, the pipeline hasn’t started; in the end block, it’s already finished.
Why Pipeline Support Rocks
Adding pipeline support to your parameter gives you powerful functionality for free — your functions instantly scale. Let’s see this in action by making the Convert-Text2Voice example function from Part 2 pipeline-aware:
function Convert-Text2Voice
{
param
(
[String]
$Text = (Read-Host -Prompt 'Enter the text to speak') ,
[ValidateRange(-10,10)]
[int]
$Speed = 0
)
Add-Type -AssemblyName System.speech
[System.Speech.Synthesis.SpeechSynthesizer]$speak =
[System.Speech.Synthesis.SpeechSynthesizer]::new()
$speak.Rate = $Speed
$speak.Speak($Text)
$speak.Dispose()
}
The [Parameter()] attribute now lets $Text receive pipeline input (results from an upstream command). It can also make the parameter mandatory, eliminating the need for Read-Host workarounds:
function Convert-Text2Voice
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
[String]
$Text ,
[ValidateRange(-10,10)]
[int]
$Speed = 0
)
process
{
# do once at the beginning (initialization tasks)
Add-Type -AssemblyName System.speech
[System.Speech.Synthesis.SpeechSynthesizer]$speak =
[System.Speech.Synthesis.SpeechSynthesizer]::new()
$speak.Rate = $Speed
# repeat for each pipeline element
$speak.Speak($Text)
# do once at the end (cleanup tasks)
$speak.Dispose()
}
}
The function still supports arguments but now also works with pipeline data:
PS C:\> Convert-Text2Voice 'Here is the current date and time:'
PS C:\> Get-Date -Format 'dddd, dd. MMMM m " past " H' | Convert-Text2Voice
Pipeline support makes your function scale: you can narrate entire plays (or log files) line by line. (Feel free to replace the file path with something more entertaining.)
PS> Get-Content C:\windows\DPINST.LOG | Convert-Text2Voice
Pipeline data is processed in the process block, which runs repeatedly—once for each incoming pipeline element.
Optimizing: Begin, Process, End
To make your functions more efficient, PowerShell script blocks have three sections: begin, process, and end.
Code that runs once at the start (setup, initialization, etc.) belongs in begin. Cleanup code that runs once at the end (freeing memory, deleting temp data, etc.) goes in end.
In our example, setting up the speech API fits best in begin, while disposing it and freeing memory belongs in end.
This lets the function focus solely on narration inside process, making it work even better:
function Convert-Text2Voice
{
param
(
[Parameter(Mandatory,ValueFromPipeline)]
[String]
$Text ,
[ValidateRange(-10,10)]
[int]
$Speed = 0
)
begin
{
# do once at the beginning (initialization tasks)
Add-Type -AssemblyName System.speech
[System.Speech.Synthesis.SpeechSynthesizer]$speak =
[System.Speech.Synthesis.SpeechSynthesizer]::new()
$speak.Rate = $Speed
}
process
{
# repeat for each pipeline element
$speak.Speak($Text)
}
end
{
# do once at the end (cleanup tasks)
$speak.Dispose()
}
}
Related links
- ScriptRunner ActionPacks will help you automate tasks
- Try out ScriptRunner here
- ScriptRunner: Book a demo with our product experts

