Mathias R. Jessen has provided the crucial pointer:
# PSv5+ syntax:
# Construct (create an instance of) the [verb] class and call its
# .GetValidValues() instance method.
[verb]::new().GetValidValues() # Returns a [string[]] array of valid values.
Your [verb]
class
implements the [System.Management.Automation.IValidateSetValuesGenerator]
interface (for use in [ValidateSet]
attributes to allow constraining parameter values to a dynamically generated set of valid (permissible) values).
This interface, has a single instance method, .GetValidValues()
, which returns the permissible values, and which PowerShell calls behind the scenes during parameter validation.
Therefore, in order to call this method yourself, you need to create an instance of your [verb]
class first:
In PowerShell v5+, the best choice is to use the static ::new()
method, which is PowerShell's way of exposing public constructors; that is, [verb]::new()
is equivalent to new verb()
in C#.
In older PowerShell versions you must use the New-Object
cmdlet for calling constructors; the equivalent of [verb]::new()
is New-Object verb
# PowerShell v5+
[verb]::new().GetValidValues()
# PowerShell v4-, but also works in higher versions.
(New-Object verb).GetValidValues()
Syntax pitfalls:
::new()
uses method syntax (as in C#), whereas New-Object
, as a cmdlet, uses command syntax,[1] i.e. is invoked like a shell command: no (...)
around the list of arguments, whitespace as the argument separator.
The following example - using a constructor with arguments - illustrates the difference:
# PSv5+ ::new() call - method syntax.
# Equivalent of this C# constructor call:
# new Regex("^\w+=.+", RegexOptions.Multiline, new Timespan(1000));
[regex]::new('^\w+=.+', [System.Text.RegularExpressions.RegexOptions]::Multiline, [timespan]:new(1000))
# Equivalent New-Object call - command syntax,
# using verbose *named* parameter binding.
# Note the following:
# * absence of (...) around the list of arguments as a whole
# * use of whitespace to separate arguments (and also parameter names from their arguments)
# * the need to separate the *constructor* arguments with ","
# as they must be passed as an *array*.
# * the need to enclose [System.Text.RegularExpressions.RegexOptions]::Multiline individually in (...)
New-Object -TypeName regex -ArgumentList '^\w+=.+', ([System.Text.RegularExpressions.RegexOptions]::Multiline)
# Equivalent call using *positional* (unnamed) parameter binding.
New-Object regex '^\w+=.+', ([System.Text.RegularExpressions.RegexOptions]::Multiline)
A particular pitfall is when a constructor takes a single argument that is an array or a collection, which with New-Object
requires wrapping the array in an aux., transitory array:
$array = 1, 2
# OK: Initialize an ArrayList instance via an array that
# binds as a whole to the `System.Collections.ICollection c`
# constructor parameter.
[System.Collections.ArrayList]::new($array)
# !! BROKEN
# $array is interpreted as *multiple* (two separate) arguments.
New-Object System.Collections.ArrayList -ArgumentList $array
# OK
# Need to wrap the array in an aux. transitory array.
New-Object System.Collections.ArrayList -ArgumentList (, $array)
[1] In PowerShell terms, method syntax is parsed in expression mode, whereas command syntax is parsed in argument mode. See the conceptual about_Parsing help topic.