PowerShell Parameter Validation: Building a Better ValidatePattern with ValidateScript

Let’s start out by taking a look at what the PowerShell built-in help says about the ValidatePattern and ValidateScript validation attributes:

about-fap2.png

Here’s what that help topic says about ValidatePattern:

validate-pattern.png

We’ll test using ValidatePattern with an example that I used in my entry for advanced event #4 in the Script Games this year as shown in the following example:

function Test-ValidatePattern {

  [CmdletBinding()]
  param(
    [Parameter(Mandatory)]
    [ValidatePattern("^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+\.html?$")]
    [string]$FileName
  )

  Write-Output $FileName

}

Who knows what that regular expression does? The guy who wrote this might, but probably no one else, especially not the junior level administrators or help desk staff who will be using this tool once it’s finished.

One of the feedback comments I received on that particular scripting games entry was “I wish I knew what this regular expression did ?”. The problem with the error messages that are generated by ValidatePattern is they tell you that your input didn’t match the regular expression. How many tool users do you know who read regular expressions? Not many unless the tool user is also the toolmaker. They prefer error messages in their native language (English in the case of my tool users).

Based on the error message in the screenshot below, my junior level administrators and help desk staff will have no idea what they did wrong, nor will they know what to do to correct the problem if they receive this error:

validate-pattern-error.png

The argument “con.html” does not match the
“^(?!^(PRN|AUX|CLOCK$|NUL|CON|COMd|LPTd|..*)(..+)?$)[^
x00-x1f\?*:”;|/]+.html?$” pattern. Supply an argument that matches
“^(?!^(PRN|AUX|CLOCK$|NUL|CON|COMd|LPTd|..*)(..+)?$)[^x00-
x1f\?*:”;|/]+.html?$” and try the command again.

ValidateScript to the rescue! Here’s what the help says about ValidateScript:

validate-script.png

This might be a little more work, but trust me, it will save you a lot of support calls and emails down the road when someone else tries to use this tool and receives the parameter validation error message.

function Test-ValidateScript {

  [CmdletBinding()]
  param (
    [Parameter(Mandatory)]
    [ValidateScript({
      If ($_ -match "^(?!^(PRN|AUX|CLOCK\$|NUL|CON|COM\d|LPT\d|\..*)(\..+)?$)[^\x00-\x1f\\?*:\"";|/]+\.html?$") {
        $True
      }
      else {
        Throw "$_ is either not a valid filename for an HTML file or it is not recommended. See this MSDN article for more information: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#naming_conventions"
      }
    })]
    [string]$FileName
  )

  Write-Output $FileName

}

validate-script-error.png

Test-ValidateScript : Cannot validate argument on parameter 'FileName'. con.html is
either not a valid filename for an HTML file or it is not recommended. See this MSDN
article for more information: https://msdn.microsoft.com/en-us/library/windows/desktop/aa3
65247(v=vs.85).aspx#naming_conventions

While this may not be the best error message in the world, any error message is better than the one previously returned by the ValidatePattern validation attribute.

µ