When building scripts and functions in PowerShell, a good habit to get into is figuring out the parameters and its expected inputs. This is commonly called parameter validation.

It's never a good idea to insert anything static into your script or function if you feel that it might change at some point in time. For example, if you have a function that checks against a remote computer, you'd never put the actual computer name into the function because this would limit your ability to use it for other computers as well.

After you’ve decided on a parameter, the next step is envisioning what users will pass to that parameter. It's always a good idea to strictly limit what arguments can be passed to a parameter so that you can expect what will come into the function and write code to account for those things. You can do this using parameter validation. Luckily for us, PowerShell has a ton of great parameter validation attributes we can use. Let's go over a few examples of what you can do with parameter validation.

There are eight different parameter validation attributes. Some are used more frequently than others. But first, how is parameter validation implemented anyway?

Let's start with a simple PowerShell function.

function Get-LoggedOnUser
 {
     [CmdletBinding()]
     param
     (
         [string]$ComputerName
     )
     
     Get-WmiObject –ComputerName $ComputerName –Class 'Win32_OperatingSystem'
 }

This function has a single parameter. Right now, it has no parameter validation. This means I can pass anything I want to the $ComputerName parameter.

Without parameter validation

Without parameter validation

Notice that I was able to pass some bogus string, which then was processed by Get-WmiObject, which failed. We need to ensure that only valid computer names are passed to the function before it gets to that point. We need to gracefully catch errors like that as soon as possible. The best way to do this by using a parameter validation attribute.

Designing proper parameter validation is an art. It can be done in some different ways. The purpose is to strictly limit what you expect to be passed to the parameter. In this example, I need to ensure that $ComputerName is an actual computer name and that it is reachable.

To do that, we need to first define what a computer name is. It may sound obvious, but you'd be surprised. Will a computer name ever have a space in it? No. Will a computer name ever have a slash in it? No. Then why are you allowing that to be passed to the function? Also, the computer must be online before it can be queried using Get-WmiObject. Why are you allowing offline computers to be passed through when you know ahead of time that Get-WmiObject is going to fail? These are the kinds of questions you need to ask when designing parameter validation.

First, let’s ensure that $ComputerName contains only valid characters. In this case, I'm going to limit this to letters and numbers. This is done using the ValidatePattern attribute. Every parameter validation attribute is placed above the parameter itself, enclosed in brackets, with the name of the attribute followed by a set of parentheses.

function Get-LoggedOnUser
 {
     [CmdletBinding()]
     param
     (
         [Parameter()]
         [ValidatePattern('^\w+$')]
         [string]$ComputerName
     )
     Get-WmiObject –ComputerName $ComputerName –Class 'Win32_OperatingSystem'
 }

You might notice that I'm using a regular expression here. This is how PowerShell can attempt to make matches against whatever is passed to $ComputerName. This pattern limits what the user can pass to the parameter to a string with only letters and numbers.

Let's try that example from above again and see what it does now.

Using a regular expression

Using a regular expression

You can now see that it was caught before it ever got to Get-WmiObject. Great! But what if we pass a legitimate computer name, but it's offline, or doesn't even exist? It's going to hang for a while, while Get-WmiObject tries to query it, and then will finally error out.

Errors encountered

Errors encountered

Let's ensure that the computer is reachable before attempting to query it via WMI. To do that, we can use another parameter validation attribute called ValidateScript. This one allows you to run just about any kind of code you'd like against the parameter argument.

function Get-LoggedOnUser
 {
     [CmdletBinding()]
     param
     (
         [Parameter()]
         [ValidatePattern('^\w+$')]
         [ValidateScript({ Test-Connection -ComputerName $_ -Quiet -Count 1 })]
         [string]$ComputerName
     )
     Get-WmiObject –ComputerName $ComputerName –Class 'Win32_OperatingSystem'
 }

You can see that I've simply added another attribute, but this time, I'm running Test-Connection against the parameter argument represented by $_ in the script block.

Now, running the function catches that computer name and fails faster.

Subscribe to 4sysops newsletter!

Test connection against the parameter argument

Test connection against the parameter argument

We've covered only a couple simple examples of parameter validation. Between all of the attributes that are available to you, you have the ability to limit just about any kind of parameter input you can think of. The next time you build a script or function with parameters, always include parameter validation and limit what can be passed to it.

0 Comments

Leave a reply

Your email address will not be published.

*

© 4sysops 2006 - 2023

CONTACT US

Please ask IT administration questions in the forums. Any other messages are welcome.

Sending

Log in with your credentials

or    

Forgot your details?

Create Account