Quick Links

Error handling is often one of the most time consuming and tedious aspects of programming. PowerShell advanced functions have the very useful ability to leverage a multitude of ways to validate parameters before they are evaluated by the function as a whole. Avoiding bad data through parameter validation makes a programmer's job that much easier.

In the past, errors that have been passed back to the user were not always very useful. Starting in PowerShell Core and continuing in PowerShell 7, the ability to define a custom error message has become possible. Instead of using a default error based on the parameter decoration, instead, you can define your own. Learn how to enhance your advanced functions to take advantage of this new functionality!

What is the ErrorMessage property?

You may have seen a parameter decorator such as ValidateScript before and, if used, found that the error message was not always the most descriptive. Often it is useful to craft your own message that more accurately reflects what the function is doing and why you may have an error. Three parameter validation decorators have the extra ErrorMessage property available to them.

  • ValidateSet
  • ValidateScript
  • ValidatePattern

What does this property actually do? First, let's look at the old way of doing this. In the example code below, we are using ValidatePattern to test if a string is 8 digits. If a fully-numeric string is not supplied, then we receive an error that could be considered cryptic and not very helpful to the user of your function.

        Function Test-ValidatePattern {
    [CmdletBinding()]
    Param (
        [ValidatePattern('^\d{8}$')]
        [String]$Digits
    )

    Process {
      Write-Output $Digits
    }
}

Where does ErrorMessage come in then? Well, by simply adding in the additional property and specifying an error message to display to the end-user, we can make the function much more useful and user-friendly.

        Function Test-ValidatePattern {
    [CmdletBinding()]
    Param (
        [ValidatePattern('^\d{8}$',ErrorMessage = "Please use an 8 digit numeric value.")]
        [String]$Digits
    )

    Process {
      Write-Output $Digits
    }
}

Extending the ErrorMessage Functionality

Utilizing the ErrorMessage parameter makes for a much more user-friendly error display. One aspect that is missing is the value that is passed in itself. In the original default error message, you may have noticed that both the value passed in and the validation regex pattern itself were shown in the error message. Thankfully, using a syntax similar to the format operator in PowerShell, we can include those values in our error message as well.

  • {0} - The passed in value.
  • {1} - The regex pattern.
        Function Test-ValidatePattern {
    [CmdletBinding()]
    Param (
        [ValidatePattern('^\d{8}$',ErrorMessage = "{0} is not an 8 digit numeric value fitting the pattern, {1}")]
        [String]$Digits
    )

    Process {
      Write-Output $Digits
    }
}

This syntax works on all three validation decorators and in the same way. The first formatting parameter is the text representation of the value being passed in while the second formatting parameter is either the set, script, or pattern that the value is being compared against.

Further Examples of Utilizing ErrorMessage

To illustrate how using ErrorMessage within your ValidateSet, ValidateScript, and ValidatePattern decorators can further move the validation steps from within your begin or process blocks to the parameters themselves, let's take a look at a function utilizing all three parameter decorators.

        Function Get-Computer {
  [CmdletBinding()]
  Param (
    [ValidatePattern('^NET-\d{8}$',ErrorMessage = "{0} is not an 8 digit numeric value preceded by 'NET-' fitting the pattern, {1}")]
    [String]$ComputerName,

    [ValidateSet('Desktop','Laptop','Mobile',ErrorMessage = "{0} is not one of the allowed devices, {1}")]
    [String]$Type,

    [ValidateScript({
      $_ -GT (Get-Date)
    },ErrorMessage = "The expiration date, {0}, is not greater than the current date per the following script: {1}")]
    [DateTime]$ExpirationDate
  )

  Process {
    [PSCustomObject]@{
      "ComputerName" = $ComputerName
      "Type" = $Type
      "ExpireDate" = $ExpirationDate
    }
  }
}

As you can see, as each parameter was validated, the execution would stop if the value did not pass. If you supply multiple bad values, only the first one will actually error out and the following errors will not display until that value has been corrected.

Conclusion

Adding additional functionality for the ValidateSet, ValidateScript, and ValidatePattern parameter decorators is a big win for the usability of PowerShell advanced functions. Instead of cryptic error messages that are of minimal value to the user running the function, proper error messages can be shown that give insight as to what has gone wrong. This moves the error handling to a higher level than the begin or process blocks which makes for cleaner and more concise code.

Since this functionality is available in PowerShell Core and PowerShell 7, you will need a newer version of PowerShell to take advantage of this functionality. With the upgrade comes numerous speed, security, and functionality benefits as well. Enhance your advanced functions with this useful property and make life easier for the users of your functions today!