How To Validate Parameters in PowerShell
No matter how skilled you are in coding, mistakes can happen. Here's how to spot the errors.
- By Adam Bertram
When coding in a script, or even in a fully-featured software application, it's important to account for as many scenarios as possible. To limit the number of possible scenarios, it's a best practice to incorporate some kind of input validation into your code. Input validation, in its simplest terms, is just putting some kind of constraint on the kind of information the user can pass to your script.
Perhaps your script exposes a -ComputerName parameter to enable the user of your script to run it against different computers. Or maybe it has a -FilePath parameter to enable the user to run your script against different files. These options open up your script to user input. The moment you allow a user to dictate what goes into your script is the moment your well-laid plans for how the script execution should go have the potential to fail miserably. For example, a -ComputerName parameter is innocent enough. You just want to allow the user to run your code against different computers, right? What could go wrong? Your initial inclination is simply to think the user will only point your script to a computer that meets all of your requirements -- like its DNS record can be resolved, it's on the network and it meets all of your presumed prerequisites. But sadly, you'd be wrong.
Users (and even you yourself) will eventually run your script in a situation you'd never have anticipated. It's impossible to guess all of the scenarios and code for them. If everything can't be accounted for, the next best thing is to limit the number of possible scenarios. This is where input validation comes in. Input validation can be incorporated in many different ways, but the topic we'll be concentrating on today is parameter validation using PowerShell's "advanced" functionality by employing the CmdletBinding statement.
Adding the CmdletBinding keyword to both PowerShell scripts and functions gives the script writer the ability to use advanced parameter validation (among many other things). Using parameter validation enables you to add multiple validation routines for different tasks to any script or function that uses the CmdletBinding keyword.
Parameter validation is applied on a per-parameter basis, as you can see in the following screenshot. In this example, I'm using the ValidatePattern attribute, which you'll see in a minute.
In total, PowerShell provides eight different restrictive validation attributes.
When one of these attributes is added to your advanced function or script, you gain control over what is passed to your script/function. Each attribute accomplishes different tasks. But you'll probably notice that once you start using these, you tend to use more of some and less of others. For this article, I'd like to concentrate on the top two attributes that I've found the most useful: ValidatePattern and ValidateScript.
ValidatePattern is an attribute that is typically used to validate a string or collections of strings. This attribute uses the power of regex to validate any kind of string you expect, and it will throw a terminating error if a value that is passed does not match the regex pattern. Let's go over an example of using a single string with ValidatePattern.
As you can see in this example, I'm using the regex pattern ^[A-Z]$. This is a very simple pattern that only allows one capital letter from A-Z as the parameter argument. You'll notice I passed an argument (in this case, blahblah) that did not match the pattern, and it failed to process the rest of the function.
Now, let's try an argument that will work.
I'm now using a parameter that matches the pattern (in this case, the capital letter A), and it works as we intend.
ValidateScript is the one validation attribute I use more than any other. It essentially enables you to validate just about anything, including any of the other validation attributes. Basically, it's whatever you can write in a script to get it to return a $True value. One of the most frequent uses of ValidateScript I've found myself using is with a -ComputerName parameter. I use ValidateScript to first ensure the computer is online before running the script/function. This way the script/function can fail cleanly instead of bombing out half-way through the script.
ValidateScript requires the use of a script block containing code that must return a $True value in order to allow the validation to permit the script/function to proceed. You'll notice that I've highlighted the brackets on either side of the code block, indicating this is encapsulated into a script block.
You'll also notice that I highlighted the pipeline variable. This is the variable that represents the parameter argument value, or $MyParameter in our case. You'll see that it failed because it tried to run Test-Connection against a computer called somerandomstuff, which obviously failed. And as you would expect, if we pass something that can be pinged by Test-Connection, it will work.
This is just one example of using ValidateScript. You can get as simple, or as fancy, as you need with it. I've also used it to do things like check for the existence of files with Test-Path, or even to ensure servers have appropriate services enabled prior to running. The world is your oyster with this one.
Using validation is not a required part of your script writing. If the circumstances are just right, your script will work without it. But being a good script writer is about accounting for the other 99,000 situations where your script has the potential to fail.
Adam Bertram is an independent consultant, technical writer, trainer and presenter. Adam specializes in consulting and evangelizing all things IT automation mainly focused around Windows PowerShell. Adam is a Microsoft Windows PowerShell MVP, 2015 powershell.org PowerShell hero and has numerous Microsoft IT pro certifications. He is a writer, trainer and presenter and authors IT pro course content for Pluralsight. He is also a regular contributor to numerous print and online publications and presents at various user groups and conferences. You can find Adam at adamtheautomator.com or on Twitter at @adbertram.