PowerShell Advanced Functions: Can we build them better? With parameter validation, yes we can!
This blog article is the second in a series of blog articles that is being written on PowerShell advanced functions for PowerShell blogging week. If you haven't already read the first article in this series: Standard and Advanced PowerShell functions written by PowerShell MVP Francois-Xavier Cat I recommend reading it also.
What is parameter validation? In PowerShell, parameter validation is the automated testing to validate the accuracy of parameter values passed to a command.
Why validate parameter input? The question should be, can your function complete successfully without valid input being provided? If not, parameter validation should be performed to catch problems early on and before your function performs any actions. There could also be security risks associated with accepting input that isn't validated.
In this first example, no parameter validation is being performed:
1function Test-NoValidation {
2 [CmdletBinding()]
3 param (
4 $FileName
5 )
6 Write-Output $FileName
7}
This allows any number of values and any value including null, empty, or invalid file names to be
provided for the FileName
parameter:
There are several different parameter validation attributes that can be used to validate the values that are provided for parameter input.
ValidateLength
is one of those attributes. It validates that the number of characters are within a
specified range as shown in the following example where the value provided for the FileName
parameter must be between one and twelve characters in length:
1function Test-ValidateLength {
2 [CmdletBinding()]
3 param (
4 [ValidateLength(1,12)]
5 [string]$FileName
6 )
7 Write-Output "$FileName is $($FileName.Length) characters long"
8}
Typing the FileName
variable as a [string] prevents more than one value from being provided for it
as shown in the previous example.
Values outside the specified character length generate an error:
ValidateLength
probably isn't the best parameter validation attribute for validating something
like a file name since it allows invalid file name characters to be specified.
ValidatePattern
validates the input against a regular expression:
1function Test-ValidatePattern {
2 [CmdletBinding()]
3 param (
4 [ValidatePattern('^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$')]
5 [string]$FileName
6 )
7 Write-Output $FileName
8}
If the value doesn't match the regular expression, an error is generated:
As you can see in the previous example, the error messages that ValidatePattern
generates are
cryptic unless you read regular expressions and since most people don't, I typically avoid using it.
The same type of input validation can be performed using ValidateScript
while providing the user
of your function with a meaningful error message.
ValidateScript
uses a script to validate the value:
1function Test-ValidateScript {
2 [CmdletBinding()]
3 param (
4 [ValidateScript({
5 If ($_ -match '^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+$') {
6 $True
7 }
8 else {
9 Throw "$_ is either not a valid filename or it is not recommended."
10 }
11 })]
12 [string]$FileName
13 )
14 Write-Output $FileName
15}
Notice the meaningful error message:
ValidateCount
limits the number of values that can be provided:
1function Test-ValidateCount {
2 [CmdletBinding()]
3 param (
4 [ValidateCount(2,6)]
5 [string[]]$ComputerName
6 )
7 Write-Output "The ComputerName array contains $($ComputerName.Count) items."
8}
Typing the variable as a [string[]] allows multiple values to be provided.
Specifying too few or too many values generates an error:
ValidateRange
verifies the value is within a specific numeric range:
1function Test-ValidateRange {
2 [CmdletBinding()]
3 param (
4 [ValidateRange(1582,9999)]
5 [int]$Year
6 )
7 Write-Output "$Year is a valid Gregorian calendar year"
8}
Verify the input is between 1582 and 9999:
ValidateSet
specifies a specific set of valid values:
1function Test-ValidateSet {
2 [CmdletBinding()]
3 param (
4 [ValidateSet('CurrentUser','LocalMachine')]
5 [string]$StoreLocation
6 )
7 Write-Output $StoreLocation
8}
Beginning with PowerShell version 3, those values will tab expand in the PowerShell console and they'll show up in intellisense in the PowerShell ISE (Integrated Scripting Environment) and most third party products such as SAPIEN PowerShell Studio.
In the previous examples, the parameters weren't designated as being mandatory however. This means that they aren't required to be specified:
Mandatory parameters require the user to provide a value:
1#Requires -Version 3.0
2#Requires -Version 3.0
3function Test-ValidateSet {
4 [CmdletBinding()]
5 param (
6 [Parameter(Mandatory)]
7 [ValidateSet('CurrentUser','LocalMachine')]
8 [string]$StoreLocation
9 )
10 Write-Output $StoreLocation
11}
If a mandatory parameter isn't specified, you're prompted for a value:
Default values can't be used with mandatory parameters. If a default value is specified with a mandatory parameter and the parameter isn't specified when calling the function, you'll still be prompted for a value (the default value will never be used).
ValidateNotNullOrEmpty
prevents null or empty values from being provided and default values can be
used with this particular validation attribute:
1function Test-NotNullOrEmpty {
2 [CmdletBinding()]
3 param (
4 [ValidateNotNullOrEmpty()]
5 [string]$ComputerName = $env:COMPUTERNAME
6 )
7 Write-Output $ComputerName
8}
The default value is used when the parameter isn't specified:
I've demonstrated the more common parameter validation attributes in this blog article, to learn more see the about_Functions_Advanced_Parameters help topic:
1help about_Functions_Advanced_Parameters -ShowWindow
Be sure to keep an eye on the #PSBlogWeek hash tag on twitter and the PSBlogWeek twitter list that I've created to know when each of the additional articles in this series of blog articles are published throughout the remainder of the week.
Also, be sure to take a look at my blog article The mother of all PowerShell blogs week is coming next week! that I published last week to learn who the bloggers are that are participating in PowerShell blogging week.
Update - April 5, 2015:
Yesterday was the last day in the PowerShell blogging week series so I thought I would add direct links to all of the articles since it has now concluded.
Name | PSBlogWeek Article |
---|---|
Francois-Xavier Cat | Standard and Advanced PowerShell functions |
Mike F Robbins | PowerShell Advanced Functions: Can we build them better? With parameter validation, yes we can! |
Adam Bertram | #PSBlogWeek – Dynamic Parameters and Parameter Validation |
Jeffery Hicks | PowerShell Blogging Week: Supporting WhatIf and Confirm |
June Blender | Advanced Help for Advanced Functions – #PSBlogWeek |
Boe Prox | A Look at Try/Catch in PowerShell |
µ