PowerShell Pipeline
Anatomy of a PowerShell Parameter, Part 2: Validation
Continuing the look into parameters, this part will focus specifically on parameter sets and the different ways to validate them.
Continuing from where I left off in my previous article on PowerShell parameters where I talked about defining the types and naming considerations, we will now take a look at some useful attributes that you can use to enhance your parameters by providing useful validations against the data being supplied. Along with that, we will look at how parameter sets can be used to ensure that only certain parameters can be paired up with others if used.
Working with Parameter Sets
There are times when you want the user to only have a certain set of parameters available after they make their initial choice. This can ensure that you are not accidently adding a parameter that will serve no purpose with the other parameter or, even worse, could cause issues within your code and end up throwing an error.
We make this happen via the ParameterSetName field in the Parameter() attribute. By specifying unique names for each set of parameters, we can ensure that they are properly separated and cannot be used together.
Param (
[ValidateCount(1,6)]
[parameter(Position=0,Mandatory=$True,HelpMessage='Please enter a computer name.',ParameterSetName='Computername')]
[string[]]$Computername,
[parameter(Position=0,ParameterSetName='Object')]
[object[]]$InputObject
)
Trying to use this function with both parameters will result in an error talking about that the set cannot be resolved.
Another interesting thing here is that if you use the tab completion, then the other named parameter from a different set won't even be available to use. Now what if we have a parameter that should be available to more than one set? We can simply leave the parametersetname blank on that parameter or we have to add the Parameter() attribute for each parameter set that we need our particular parameter available for.
Param (
[parameter(Position=0,Mandatory=$True,HelpMessage='Please enter a computer name.',ParameterSetName='Computername')]
[string[]]$Computername,
[parameter(Position=0,ParameterSetName='Object')]
[object[]]$InputObject,
[parameter(ParameterSetName='Object')]
[parameter(ParameterSetName='Computername')]
[int]$Timeout
)
Validating Parameter Data Using Attributes
A lot of times, we may end up performing some sort of validation of the data being supplied to parameters after the fact somewhere in the script. Rather than taking time with that you can take advantage of the already available validation attributes that can do the work for you!
The available attributes that you can use are:
- AllowNull
- AllowEmptyString
- AllowEmptyCollection
- ValidateCount
- ValidateLength
- ValidatePattern
- ValidateRange
- ValidateScript
- ValidateSet
- ValidateNotNull
- ValidateNotNullOrEmpty
I won't go into every one of these in detail but will cover a few of the attributes that I feel will be used more commonly than the rest of the group.
ValidateCount
Using ValidateCount means that you can limit how many items in a collection that you supply to a parameter. This allows you to set a minimum and a maximum value to validate against.
Param (
[ValidateCount(1,6)]
[string[]]$Computername
)
ValidateSet
ValidateSet is a very useful attribute that allows you to specify a specific list of items that will be accepted as the parameter value. By doing this, you also enable users to tab through the possible values once you specify the parameter that this is being used against.
Param (
[ValidateSet('Left','Right','Up','Down')]
[string[]]$Computername
)
We can see in the PowerShell ISE that intellisense shows the possible values for the parameter.
If we specify the wrong value for the parameter, an error is thrown as a result. The nice thing about the error is that it will show you what values are acceptable.
ValidateNotNullOrEmpty
This is a useful attribute when you combine it with the Mandatory setting for the parameter attribute. If a user were to try and force a null value or an empty string ('') at the mandatory prompt, it would throw an error when it checks for a value on the parameter.
Param (
[ValidateNotNullOrEmpty()]
[parameter(Mandatory=$True)]
[string[]]$Computername
)
ValidatePattern
This is a more unique validation attribute in that it allows you to use Regular Expressions (RegEx) to validate the data coming into the parameter and as long as it matches the expected pattern, will let it through, otherwise it will throw an error back to the user. The downside to this is that the error is showing the RegEx pattern that was used to perform this validation. I don't know about you, but RegEx can be difficult to read as you make it more and more complex and it is hard to expect a consumer of the script to know what that pattern means. That being said, this leads us up to the last validation attribute: ValidateScript
Param (
[ValidatePattern('^(?:\d{3}-){2}\d{4}$')]
[parameter(Mandatory=$True)]
[string[]]$PhoneNumber
)
ValidateScript
This was one was saved for last as it is extremely powerful validation attribute to use. You can supply a scriptblock that can be used to check the value of the parameter assigned and then either throw an error using Throw, or return back a Boolean value of $True to allow the value to be used within the script. What is nice about this over ValidatePattern is that you can still use the RegEx pattern but now if the value isn't a match, you can throw a more useful error that the user can actually understand.
Param (
[ValidateScript({
If ($_ -match '^(?:\d{3}-){2}\d{4}$') {
$True
}
Else {
Throw "You need to provide a phone number matching this format: 555-555-5555"
}
})]
[parameter(Mandatory=$True)]
[string[]]$PhoneNumber
)
With that, you can now go out and enhance your current functions by adding more power to your parameters to validate parameters and ensure that they are organized properly where necessary using parameter sets.
About the Author
Boe Prox is a Microsoft MVP in Windows PowerShell and a Senior Windows System Administrator. He has worked in the IT field since 2003, and he supports a variety of different platforms. He is a contributing author in PowerShell Deep Dives with chapters about WSUS and TCP communication. He is a moderator on the Hey, Scripting Guy! forum, and he has been a judge for the Scripting Games. He has presented talks on the topics of WSUS and PowerShell as well as runspaces to PowerShell user groups. He is an Honorary Scripting Guy, and he has submitted a number of posts as a to Microsoft's Hey, Scripting Guy! He also has a number of open source projects available on Codeplex and GitHub. His personal blog is at http://learn-powershell.net.