15

I am using the ValidateSet attribute on one of my PowerShell function parameters like so:

[ValidateSet('Development','Test','Production')]
[string]$Context

I have repeated this is many places throughout a scripting project. Can these literal strings be replaced with a constant?

2 Answers 2

12

No, it has to be a literal or a scriptblock. The scriptblock option seems pointless since it seems to use the literal (string) value of the scriptblock instead of executing it.

So effectively, from my testing, you must use literals.

If you use a dynamic parameter instead you could achieve this, but that's way overkill just to be DRY.

If you try to use a variable, it won't work (and ISE will give you the red squiggly). The help text erroneously says it must be a constant, but it means literal.

I created a constant with:

Set-Variable -Option Constant

And it still does not work.

Sign up to request clarification or add additional context in comments.

3 Comments

I got better results with ValidateScript. I created a function IsValidContext. At least I can keep the context strings in one place and extend the list of valid ones later without much fuss. param ( [ValidateScript({IsValidContext $_})] [string]$Context )
@MatthewMacFarland yeah, but it won't tab complete that way.
@MatthewMacFarland and by the way you can add that as another answer in case it's useful for other people :)
5

Adding this to help others searching for a similar solution. I was looking for a way to validate parameters against the keys of a global hash table. This is what I ended up doing:

$global:MyHash = @{
    "anyitem"  = @{"name" = "somename1"; "count" = 42 };
    "someitem" = @{"name" = "another name"; "count" = 1337 };
}

function Test-Hash
{
    param
    (
        [Parameter(mandatory = $true)] [ValidateScript( { $_ -in $global:MyHash.Keys } )] [string[]] $items
    )
}

Test-Hash -items anyitem, someitem

I ended up replacing ValidateSet with ValidateScript as I realized (as mentioned in this thread as well) that the code block in ValidateSet does not work at all. Instead validating against the keys of a hash table one could easily use something like

$validParams = @('opt1', 'opt2')

and in the ValidateScript codeblock

{ $_ -in $validParams }

This is basically what I assume should answer the question.

2 Comments

Globals should be avoided for the same reason as in most other languages. But you could just embed them in the script block itself. In a module you can use $Script: scope instead; which acts like a "global" within the module's code, but doesn't pollute the scope outside the module. Also note that ValidateScript won't add tab completion, and that it has bad error output when validation fails, which can be mitigated somewhat with -or $(throw "A better error message").
Learning something new every day - did not know about the script scope, seems it actually is exactly what I need - Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.