Functions and parameters
Write your own cmdlet-style functions with typed, validated parameters and pipeline input.
- Define functions with param() blocks, types, defaults and switches
- Validate input with Mandatory and Validate* attributes
- Accept pipeline input with begin/process/end, and avoid accidental output
A function is a named script block. Give it a Verb-Noun name and a param() block, and it works just like a built-in cmdlet - named parameters, tab completion and all:
1function Get-FeedingAmount {
2 param(
3 [int]$Wingspan,
4 [switch]$Hungry,
5 [string]$Food = 'goats'
6 )
7 $kg = $Wingspan * 3
8 if ($Hungry) { $kg *= 2 }
9 "$kg kg of $Food"
10}
11Get-FeedingAmount -Wingspan 12 -Hungry # 72 kg of goatsCall it like a cmdlet - no parentheses, no commas. Get-FeedingAmount(12, $true) passes a single array to the first parameter, a classic mistake.
1function Get-FeedingAmount {
2 param(
3 [int]$Wingspan,
4 [switch]$Hungry,
5 [string]$Food = 'goats'
6 )
7 $kg = $Wingspan * 3
8 if ($Hungry) { $kg *= 2 }
9 "$kg kg of $Food"
10}
11Get-FeedingAmount -Wingspan 12
12Get-FeedingAmount -Wingspan 12 -Hungry
13Get-FeedingAmount 2 -Food 'lantern moths'36 kg of goats 72 kg of goats 6 kg of lantern moths
Everything is output
Here’s the most surprising thing about PowerShell functions: every value that isn’t captured becomes part of the result, not just what follows return. return simply exits early (optionally outputting one more value).
So a stray method call that returns something - $list.Add('x') returns the new index, for example - leaks into your output. Silence it with $null = ..., [void](...) or | Out-Null.
1function Get-Names {
2 $list = [System.Collections.ArrayList]::new()
3 $list.Add('Ember')
4 $list.Add('Glim')
5 return $list
6}
7function Get-NamesQuietly {
8 $list = [System.Collections.ArrayList]::new()
9 $null = $list.Add('Ember')
10 [void]$list.Add('Glim')
11 $list
12}
13(Get-Names) -join ','
14(Get-NamesQuietly) -join ','0,1,Ember,Glim Ember,Glim
Advanced functions
Add [CmdletBinding()] above param() and your function becomes an advanced function: it gains the common parameters (-Verbose, -ErrorAction, ...) and can use parameter attributes:
| Attribute | Effect |
|---|---|
[Parameter(Mandatory)] | PowerShell asks for (or errors without) the value |
[Parameter(ValueFromPipeline)] | the parameter receives pipeline objects |
[ValidateSet('Wyrm', 'Wisp')] | only these values (and tab completion offers them!) |
[ValidateRange(1, 30)] | numbers must be in range |
[ValidateNotNullOrEmpty()] | rejects $null and '' |
[ValidatePattern('^DRG-\d{4}$')] | must match a regex |
To take pipeline input, mark a parameter ValueFromPipeline and put the work in a process {} block, which runs once per incoming object. begin {} runs once before the first, and end {} once after the last.
1function New-DragonTag {
2 [CmdletBinding()]
3 param(
4 [Parameter(Mandatory, ValueFromPipeline)]
5 [ValidateNotNullOrEmpty()]
6 [string]$Name,
7 [ValidateRange(1, 9999)]
8 [int]$Start = 1
9 )
10 begin { $number = $Start }
11 process {
12 'DRG-{0:D4} {1}' -f $number, $Name
13 $number++
14 }
15 end { Write-Verbose "Tagged up to $number" }
16}
17'Ember', 'Glim', 'Skyla' | New-DragonTag -Start 40
18try { New-DragonTag -Name 'Pebble' -Start 0 } catch { 'Rejected: Start must be 1 to 9999' }DRG-0040 Ember DRG-0041 Glim DRG-0042 Skyla Rejected: Start must be 1 to 9999
Key takeaways
Functions take a
param()block with types, defaults and[switch]parameters; call them like cmdlets.Every uncaptured value is output - silence noisy calls with
$null =or[void].[CmdletBinding()]plus[Parameter()]and[Validate*()]attributes give you robust, cmdlet-grade input.ValueFromPipelinewithbegin/process/endmakes a function work in pipelines.
Lesson quiz
7 questions · pass with 5 correct · up to 50 XP
Passing this quiz completes the lesson and keeps your streak going. Questions you miss come back in review sessions later.
Practice: write PowerShell scripts
Write a script in the editor and run it for real against sample input, which is piped into your script as $input. Scripts run on PowerShell 6.2 through Try It Online (tio.run), a free public service, so these exercises avoid PowerShell 7-only syntax; your script and test input are sent there.
Feeding calculator
Write Get-FeedingAmount with parameters -Wingspan (an [int], which must be from 1 to 30 - use [ValidateRange]) and a -Hungry switch. A dragon eats 3 kg per metre of wingspan, doubled when hungry. It returns just the number.
Each input line is a wingspan, optionally followed by hungry. The starter splits the line for you; call your function and print 12 m: 36 kg or 12 m (hungry): 72 kg.
- Three dragons
- A big one
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Tag them through the pipeline
Write an advanced function New-DragonTag that takes dragon names from the pipeline and outputs DRG-0001 Ember, DRG-0002 Glim, ... numbering from 1 with four digits. When the pipeline is finished, it outputs tagged 2 dragons. The starter pipes the input into it.
Use begin, process and end, and the format {0:D4}.
- Two dragons
- Four dragons
Lessons teach PowerShell 7; your script runs on PowerShell 6.2 via Try It Online (tio.run), a free public service, so stick to syntax that works there. Test input is piped into your script as $input. Your script and test input are sent to that service.
Questions about this lesson
Stuck? Ask. Figured something out? Share it. Explaining is one of the best ways to learn.
Loading posts…