Validating PowerShell Input Using Parameter Validation Attributes

PowerShell graphic

PowerShell provides ways to validate acceptable parameter input for a function or a script. If you have taken an introductory computer science or programming course, you have learned first-hand about the importance of validating the values of parameters passed into your script, function, or program. You were taught that your program should nicely tell the user what was wrong and how to fix the problem. You may have ended up writing thousands of lines of code to cover every possible scenario where the user could mess up the input. Perhaps, you wrote one line of code that tells the user the input does not match the desired input. Huh? Sometimes it would almost be better to throw an error! PowerShell parameter validation attributes define what is acceptable for parameter input without needing to write massive amounts of code to handle it.

 

 

Timing of Parameter Validation

The benefits to using parameter validation attributes is two-fold. First, you do not have to write the error messages yourself. You define the acceptable or non-acceptable attributes directly on the parameter and it throws the error. It is understandable and readable to the end user. Second, there is no code for the validation. You never enter the actual code if the parameter validation does not pass and the code does not get bloated from all the input checking.

Checking For Empty Parameters

Some PowerShell parameter validation attributes allow you to specifically permit a null or empty value on an input parameter. For example, the following code shows a function that does not use any parameter validation for the input parameter $ComputerName. Perhaps, the input for $ComputerName is coming from another cmdlet, process, or a file that is unknowingly empty. When passed null or empty values occur without parameter validation, the function will err.

function Do-Something {
    param (
        [Parameter(Mandatory=$True)]
        [string[]]$ComputerName
        )

    ping $ComputerName
}

ParamValidation1 ParamValidation2

Allowing Null and Empty Values

Though the error messages are fairly clear about the problem, perhaps you want to allow for these conditions to be valid so that the function does not err or give nasty red messages. There are three parameter validation settings that allow you to accept null or empty values and you can use one or all three. This depends on what kind of input you anticipate or want to accept:

  • [AllowNull()]
  • [AllowEmptyString()]
  • [AllowEmptyCollection()]

You may encounter any of these scenarios when receiving input from another cmdlet. You can now gracefully handle any of these values by adding all three to the parameter validation for $ComputerName. I have added a write-host to identify that the code has received something that I chose not to process. You could choose to include a write-verbose, a line written to a log, or any other custom handling.

function Do-Something {
    param (
        [Parameter(Mandatory=$True)]
        [AllowNull()]
        [AllowEmptyString()]
        [AllowEmptyCollection()]
        [string[]]$ComputerName
        )

        foreach ($obj in $ComputerName) {
            if (($obj -eq $Null) -or ($obj -eq '')) {
                write-host "Nothing received to ping"
                }
            else {
                ping $obj
                }
            }
    }

ParamValidation3

Disallowing Null or Empty Values

Conversely, ensure that a null or empty value is not accepted as an input parameter by using the ValidateNotNull() or ValidateNotNullorEmpty() parameter validation attributes. The behavior in the simple example, when using the validate settings, shows a similar error compared to the behavior in the original example with no parameter validation. However, when the parameters are validated, the messages are clear that the parameters are not passing validation. The original example contained messages stating that the arguments could not be bound. As a result, using validation will specifically state that you are not allowing the values. This is different from having to figure out how the function would behave with invalid parameters and rely on the default handling for the parameter.

ParamValidation4

Limiting the Input to a Parameter

At times, you may also have requirements as to what constitutes an acceptable parameter. NetBIOS limitations may limit a computer name to 15 characters or less. Perhaps, you have a specific computer naming convention that has 6 characters and 4 digits and you want to check that the input is a valid computer name. For a script with performance implications, you may want to limit the number of computers that you are running against at one time. For numeric input, you may want to limit the acceptable digits. PowerShell provides parameter validation attributes to handle all of these requirements.

  • [ValidateLength(1,15)]  — Allows for a computer name with a length of 1 to 15 characters.
  • [ValidatePattern(“[a-z]{6}\d{4}”)]  — Allows for a computer name that contains 6 characters followed by 4 digits.
  • [ValidateCount(1,3)] — Allows for 1 to 3 computer names to be specified. It throws a validation error and does not run if the number of parameters is exceeded.
  • [ValidateRange(1,12)] — Allows for an integer value of 1 to 12 to be provided. For example, this could be used for an input for a parameter $Month.

Limiting Input to Specific Parameter Values

You may also want to limit the possible values of a parameter for only a few options. For example, if you were writing a script that set ACLs on a file, you may want to limit the $Action parameter to Allow or Deny. You can use ValidateSet[(“Allow”,”Deny”)] to limit the parameter value for $Action to one of those two options.

Custom Validation

The [ValidateScript({})] parameter validation attribute allows you to define your own custom parameter validation. To pass validation, the script block must evaluate to $True. To represent the current value of the parameter being passed in, use $_. An example of this is an input parameter for a DNS name that must be resolvable for the parameter to pass validation. Note that this is only possible to validate a single parameter and not a collection. In that case, handle the validation of a collection with a foreach loop in the main code.

[ValidateScript({Resolve-DNSName -Name $_})]

There Is No (Good) Reason to Not Validate Parameters

With all the options for parameter validation at your fingertips, there is no good reason to not use it. Rather, it allows you to precisely narrow down what constitutes acceptable input for a parameter. Furthermore, validating your parameters on the declaration itself allows you to keep the validation from bloating your code unnecessarily. As a result, by using parameter validation attributes, you keep your code simple and focused on the things the code needs to do.