All solutions below work in both functions and scripts.
Most robust solution that should work in any invocation scenario, PSv2+:
param (
[ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
[String]$Type = 'Startup'
)
($MyInvocation.MyCommand.Parameters['Type'].Attributes |
Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues
A simpler, but fragile PSv3+ solution, which assumes:
that Set-StrictMode is either set to -version 1 or not set.
Set-StrictMode may have been set outside of your control, so if you don't fully control the execution environment, it is safer to use the more verbose, PSv2-compatible command above.
(The Set-StrictMode setting behaves like a variable: it is inherited by descendent scopes, but setting it in a descendent scope sets it locally (only affects that scope and its descendants).)
However, if you define a function as part of a module, the outside world's Set-StrictMode setting does not apply.
that, up to at least Windows PowerShell v5.1 / PowerShell Core v6.0-alpha16, running into this bug when repeatedly dot-sourcing a script is not a concern.
param (
[ValidateSet('Startup', 'Shutdown', 'LogOn', 'LogOff')]
[String]$Type = 'Startup'
)
(Get-Variable Type).Attributes.ValidValues
Optional background information
The PSv3+ shorthand syntax (Get-Variable Type).Attributes.ValidValues is essentially the equivalent of:
(Get-Variable Type).Attributes | ForEach-Object { $_.ValidValues }
That is, PowerShell automatically enumerates the collection .Attributes and collects the values of each element's .ValidValues property.
In the case at hand, only one attribute in the .Attributes collection - the one of subtype [System.Management.Automation.ValidateSetAttribute] - has a .ValidValues property, so that single value is returned.
Given that the other attributes have no such property, setting Set-StrictMode to -version 2 or higher causes the attempt to access a nonexistent property to raise an error, and the command fails.
((Get-Variable Type).Attributes |
Where-Object { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues
bypasses this problem by explicitly targeting the one attribute of interest (using the -is operator to identify it by type) that is known to have a .ValidValues property.
The more verbose alternative to accessing the attributes of parameter [variable] $Type with (Get-Variable Type).Attributes is to use $MyInvocation.MyCommand.Parameters['Type'].Attributes.
Use of the $MyInvocation.MyCommand.Parameters collection enables enumerating and inspecting all parameters without needing to know their names in advance.
David Brabant's answer is helpful, but (as of this writing):