Validating parameters in functions
Whenever a script or program receives data from an unknown source, the general rule is that the data should be validated prior to being used. Validation can take many forms, with simple validations such as confirming the value exists, is of the right type, or fits a predefined format. Validation can also be complex multi-stage events such as ensuring a username exists in a database before prompting for a password.
This section will review several basic validation-testing methods for use in PowerShell.
How to do it...
Here we will discuss creating a function without input validation:
Create a basic function with no input validation:
Function Hello-World { param($foo) "Hello $foo" }
Test the function using different input types.
Update the function to perform input type validations as discussed in the following steps:
Update the function to include the basic string validation.
Function Hello-WorldString { param([string] $foo) "Hello $foo" }
Test the function using different input types:
Update the function to perform basic integer validation.
Function Hello-WorldInt { param([int] $foo) "Hello $foo" }
Test the function using different input types:
Update the function to perform basic float validation.
Function Hello-WorldFloat { param([float] $foo) "Hello $foo" }
Test the function using different input types:
Update the function to perform basic array validation.
Function Hello-WorldStringArray { param([string[]] $foo) "Hello " + $foo[0] }
Test the function using different input types:
Update the functions to perform validation of input values:
Create a function to validate the length of a parameter:
function Hello-WorldLength{ param([ValidateLength(4,10)] $foo) "Hello $foo" }
Test the function using different input types:
Create a function to validate a number in a range:
function Hello-WorldAge{ param([ValidateRange(13,99)] $age) "Hello, you are $age years old" }
Test the function using different input types:
Create a function to validate a set of parameters:
function Hello-WorldSize{ param([ValidateSet("Skinny", "Normal", "Fat")] $size) "Hello, you are $size" }
Test the function using different input types:
Create a function that validates against a script:
function Hello-WorldAge2{ param([ValidateScript({$_ -ge 13 -and $_ -lt 99})] $age) "Hello, you are $age years old" }
Test the function using the different input types:
Create a function to validate the input as a phone number:
Function Test-PhoneNumber { param([ValidatePattern("\d{3}-\d{4}")] $phoneNumber) Write-Host "$phoneNumber is a valid number" }
Execute the
Test-PhoneNumber
function using different input types:
Use custom validation to test parameters inside our function:
Update the function to use custom validation internal to the script with regular expressions:
Function Test-PhoneNumberReg { param($phoneNumber) $regString=[regex]"^\d{3}-\d{3}-\d{4}$|^\d{3}-\d{4}$" if($phoneNumber -match $regString){ Write-Host "$phoneNumber is a valid number" } else { Write-Host "$phoneNumber is not a valid number" } }
Test the function using different input types:
How it works...
We start off with a simple Hello-World
function with no input validation. Three different calls to the function are performed, one with a username (as the function was designed to work), one with a number, and yet another without any parameters. As you can see, all three commands complete successfully without returning errors.
In the first group of functions in the steps 3 to 10, we see a set of examples using Type Validation to confirm the parameters are of a specific type. There are four iterations of the Hello-World
example that accept a string
, integer
, float
, and array
as inputs. As you see from the calls to Hello-WorldString
, both text and numbers are viewed as strings and return successfully. However, the calls to Hello-WorldInt
succeed when a number is passed, but fail when text is passed.
Note
You may notice that the original number 867.5309 passed to the function Hello-WorldInt
was rounded and truncated when returned. This is because integers are whole numbers—that is, not partial numbers. When the number was cast as an integer, it was rounded to the nearest whole value, which in this case caused it to round up to 868.
In the second set of functions in steps 11 to 20, we see a set of examples using basic input validation. These functions use ValidateLength
, ValidateRange
, ValidateSet
, ValidateScript
, and ValidatePattern
attributes of the parameters to validate the input. Additionally, these validation types can be used in conjunction with the basic type validations to further ensure the input is of the correct type and value.
The last set of examples in steps 21 to 24 perform validation internal to the script, instead of relying on the in-built validation. The function named Test-PhoneNumberReg
uses a regular expression in order to validate the input as part of the script. Instead of relying on validation using types or ValidatePattern
, this function simply passes the variable to the PowerShell code in order to check the input. By managing the validation as part of the function, we have more flexibility on how we handle and present validation errors to our users, and can return a more user-friendly message to the end user.
There's more...
It is considered a best practice to perform at least basic validation for all inputs. Lack of input validation can result in the function crashing, operating unpredictably, or even resulting in damaging data in your environment. This has been a common method for computer attackers to access secure systems and should be taken diligently.
See also
More information about using regular expressions for validation can be found at http://technet.microsoft.com/en-us/magazine/2007.11.powershell.aspx
Additional information about input validation can be found by executing
help about_Functions_Advanced_Parameters