Prof. Powershell
Validation Voodoo with PowerShell Scripts
Deploying scripts with parameters? Be sure to validate input. Here are a few validation tests worth considering.
Whenever I write an advanced PowerShell function or script that uses parameters, I find it very helpful to validate any data upfront before my script gets too far. The last thing I want is my script to almost complete only to bomb out at the end because of invalid data. I'd rather have it fail immediately and avoid any unintended consequences.
In PowerShell 1 I had to write my own validation code. But now I have a number of options that I can use depending on the parameter and its expected value. You don't have to use any of them; feel free to write your own validation logic at the beginning of your script. But I think you'll find these validation tests much easier to use. Let's get started.
ValidateNotNullOrEmpty
One validation test I use frequently is to make sure that no null or empty value is passed.
Function Get-Foo {
Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="What computer do you want to process?")]
[ValidateNotNullOrEmpty()]
[string]$computername
)
Write-Host "Processing $computername" -ForegroundColor Green
}
I find this works best with mandatory parameters as it will catch any empty values (see Fig. 1)
 |
|
Figure 1. The script left me feeling a bit empty. (Click image to view larger version.) |
Because I just hit enter, the validation logic was executed and PowerShell throws an exception. Ugly, perhaps, but I'd rather have that then have my script fail part way through.
ValidationRange
Another useful test, naturally for parameters expecting an integer, is range validation. The validation attribute takes two parameters, a minimum and maximum value. I've added a parameter that must be between 1 and 50:
Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="What computer do you want to process?")]
[ValidateNotNullOrEmpty()]
[string]$computername,
[Parameter(Position=1)]
[ValidateRange(1,50)]
[int]$Count
)
If a value outside that range is passed, PowerShell throws an exception (see Fig. 2).
 |
|
Figure 2. Now, I'm feeling a range of exceptions. (Click image to view larger version.) |
ValidateSet
Related to range validation, is validation on a set or collection of possible values. In this example, the parameter Item can only use a value of User, Computer or Group:
Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="What computer do you want to process?")]
[ValidateNotNullOrEmpty()]
[string]$computername,
[Parameter(Position=1)]
[ValidateRange(1,50)]
[int]$Count,
[Parameter()]
[ValidateSet("User","Computer","Group")]
[string]$Item="User"
)
You can still set a default as I have done, but make sure it belongs to the set. You can provide a default value that doesn't belong to the set and PowerShell will NOT complain. But if you specify a value outside the set, it will (see Fig. 3).
 |
|
Figure 3. Who goes there? User, Computer, or Group? (Click image to view larger version.) |
ValidateScript
The last validation tool I want to cover is a script. The attribute uses a scriptblock with $_ representing the parameter value. You want to write the scriptblock so that it returns either True or False. Here, I modified the original Computername parameter to also test if the computer is reachable:
Param (
[Parameter(Position=0,Mandatory=$True,HelpMessage="What computer do you want to process?")]
[ValidateNotNullOrEmpty()]
[ValidateScript({Test-Connection -ComputerName $_ -Quiet -Count 2})]
[string]$computername,
[Parameter(Position=1)]
[ValidateRange(1,50)]
[int]$Count,
[Parameter()]
[ValidateSet("User","Computer","Group")]
[string]$Item="User"
)
If the scriptblock returns False then the parameter is considered a failure. Thus, if I try to pass a computername that is unreachable, the Test-Connection expression will return $False and I end up with an exception again (see Fig. 4).
 |
|
Figure 4. Alas, there are exceptions to any rule. (Click image to view larger version.) |
You can include multiple validation tests as I've done here. In this example if the user is prompted and presses Enter the first validation will catch the problem, which is what I want.
There are few more options I didn't go into, like validating against a regular expression or pattern. Take a few minutes to read About_Functions_Advanced_Parameters and you'll see others worth deploying.
About the Author
Jeffery Hicks is a Microsoft MVP in Windows PowerShell, Microsoft Certified Trainer and an IT veteran with over 20 years of experience, much of it spent as an IT consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He works today as an independent author, trainer and consultant. Jeff writes the popular Prof. PowerShell column for MPCMag.com and is a regular contributor to the Petri IT Knowledgebase and 4SysOps. If he isn't writing, then he's most likely recording training videos for companies like TrainSignal or hanging out in the forums at PowerShell.org.
Jeff's latest books are Learn PowerShell 3 in a Month of Lunches, Learn PowerShell Toolmaking in a Month of Lunches and PowerShell in Depth: An Administrators Guide.
You can keep up with Jeff at his blog http://jdhitsolutions.com/blog, on Twitter at twitter.com/jeffhicks and on Google Plus (http:/gplus.to/JeffHicks)