PowerShell Scripting with [ValidateSet]

Today we’ll continue our exploration of the parameter validation attributes you can use in you PowerShell scripting. We’ve already looked at [ValidateRange] and [ValidateScript]. Another attribute you are likely to use is [ValidateSet()]. You can use this to verify that the parameter value belongs to a pre-defined set.

To use, specify a comma separated list of possible values.

If the person running the script specifies something other than “Apple”, “Banana”, or “Cherry” as a value for -Fruit, PowerShell will throw an exception and the script will fail to run. And in case you were wondering, this is not case-sensitive.

If you are going to use this attribute, I recommend providing documentation either in comment based help and/or as part of a help message so the user knows what values to expect. The PowerShell help system doesn’t automatically detect this attribute and use it in syntax display as you might have seen with other cmdlets.

Here’s a more practical example.

The script will get recent events from a specified log on a specified computer and export the results. My script will only export from a short list of logs which I’m validating.

If an invalid value is detected PowerShell will complain.

The error message displays the expected values, but the better approach might be to include them in a help message, especially if the parameter is mandatory. For example, this script will export results based on -Export.

If you’d like to try out my demo script, you can download Demo-ValidateSet.

11 thoughts on “PowerShell Scripting with [ValidateSet]”

  1. hi

    you can use ignorecase keyword:


    PS> gc function:\test-foo

    function test-foo {
    param(
    [Parameter(Position=0)]
    [validateset('foo','bar',ignorecase=$false)]
    $test)

    $test

    }


    PS> test-foo foo
    foo

    PS> test-foo FOO
    error

  2. Jeff
    Nice work on validation. Haveyouthough of rollimg it up into a help file. (about_jh_advanced_validation) or similar.

    1. Thanks for the positive feedback. I’ll have to think about the best way to bundle everything. I still have one or two more topics to cover.

  3. Hey Jeff;
    Great article! Maybe you can point me in the right direction…. or maybe I just need to stop looking for ways to be lazy :-)

    I would like to ValidateSet against a scriptblock (similar to a ValidateScript). For example:

    function find-processid {
    [CmdletBinding()]
    param(
    [ValidateSet({(Get-Process).Name})]
    $ProcessName
    )
    $Result = (Get-Process -Name $ProcessName)
    $Result.id
    }

    This always bombs because it is reading the scriptblock literally. I know that I can make this work by changing ValidateSet to ValidateScript, the real aim here is to get tab completion to cycle through my choices in a dymanic situation (laziness).

    Do you think there a way to make ValidateSet read the scriptblock when the function is called (some funky $([]::{}.()) magic that only you and maybe one other person has ever seen) or should I be looking to use a RuntimeDefinedParameter instead?

    1. ValidateSet really seems to need to be constant and predefined. But I think you can get the same results with ValidateScript.

      param (
      [Parameter(Position=0,Mandatory=$True)]
      [ValidateScript({$(get-process | Select -expand name) -contains $_})]
      [string]$name
      )

  4. When you do that does tab completion on the -name paramter work for you? Maybe something’s wrong with my shell…

    Function Get-ProcessID{
    param (
    [Parameter(Position=0,Mandatory=$True)]
    [ValidateScript({$(get-process | Select -expand name) -contains $_})]
    [string]$name
    )
    $prc = Get-Process -Name $_
    $prc.id
    }

    get-processid -name

    Returns files in the local directory in my shell, or am I doing something else wrong?

    1. No that won’t work. What you want will work in PowerShell v3. You could type Get-Process -name press space and then tab and it would cycle through the all the current processes. You are misunderstanding what a function does. I think you should step back and regroup. Feel free to use the forum at http://bit.ly/AskJeffHicks

Comments are closed.