<WIZARD WARNING> ISVs and Tool vendors may find this important, Advanced users may find this interesting, Casual users may want to skip this.
Someone asked me if there was a programmatic way to tell what the legal values for a string parameter to a cmdlet was. The example was OUT-FILE -ENCODING xxx
Out current help doesn’t tell you this information (and it wouldn’t be a great programmatic experience even if it did) and neither does Get-Command:
PS> get-command out-file |fl Definition
Definition : Out-File [-FilePath] <String> [[-Encoding] <String>] [-Append]
[-Force] [-NoClobber] [-Width <Int32>] [-InputObject <PSObjec
t>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-Er
rorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int
32>] [-WhatIf] [-Confirm]
It tells me that it takes a string but not what the values are. When you try to assign an incorrect value, you’ll be told what the correct values are:
PS> gps |out-file foo.txt -Encoding UTF-8
Out-File : Cannot validate argument “UTF-8” because it does not belong to t
he set “unicode, utf7, utf8, utf32, ascii, bigendianunicode, default, oem”.
At line:1 char:32
+ gps |out-file foo.txt -Encoding <<<< UTF-8
That is fine for the interactive case but what about the programmatic case – can you find this info out? The answer is: maybe.
We designed PowerShell (formerly known as Monad) for this scenario. When a cmdlet developer declares their parameters, we provide them a set of VALIDATION attributes that we encourage them to use. At first glance, a developer might say – the heck with those, it would be just as simple to code this myself. BUT WAIT — DON’T DO THAT.
PSTIP: Use the Attributes Luke
There are 2 primary benefits of using the attributes instead of coding them yourself
- PowerShell engine does the work and will generate the error messages. That might sound trivial but I can guarantee you that if 100 cmdlet developers write their own code, you’ll get at least 200 error messages for the exact same condition. Using the Attributes ensures a consistent user experience.
Don’t care about your user’s experience? Then there is an economic advantage to using the attributes. Use them and Microsoft will pick up the bill for translating them into all the languages your customers want. (Consistency through economics – do you see the pattern here?)
- The attributes provide a programmable way to discover the capabilities of the cmdlet. This can be used in all sorts of wonderful ways – e.g. autogenerating GUI front end to the cmdlets. If we know what the parameters are and we also know what the valid values are, we can turn that into a combo-box instead of having the user TYPE the values.
If Cmdlet developers don’t do use the Attributes, you get none of this.
Let’s explore the CmdletInfo datastructure. This is what is returned when you do a Get-Command (gcm) on a cmdlet.
PS> gcm out-file |gm param*
TypeName: System.Management.Automation.CmdletInfo
Name MemberType Definition
—- ———- ———-
ParameterSets Property System.Collections.ObjectModel.ReadOnlyCollecti…
ParameterSets are the Sets of valid parameters (are we good at naming or what?). For instance, Get-Process (gps) can be provided an -ID parameter or a -NAME parameter. These are 2 ParameterSets for that cmdlet.
PS> gps -Name powershell
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
——- —— —– —– —– —— — ———–
1112 15 112816 19812 250 206.61 936 powershell
PS> gps -ID 936
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
——- —— —– —– —– —— — ———–
1119 15 112920 19984 250 206.66 936 powershell
Out-File has only one parameterSet
PS> (gcm out-file).Parametersets |fl name
Name : __AllParameterSets
ParameterSets have a set of Parameters. One of those is the Encoding parameter:
PS> $p=(gcm out-file).Parametersets[0].parameters |?{$_.name -eq “Encoding”}
PS> $p
Name : Encoding
ParameterType : System.String
IsMandatory : False
IsDynamic : False
Position : 1
ValueFromPipeline : False
ValueFromPipelineByPropertyName : False
ValueFromRemainingArguments : False
HelpMessage :
Aliases : {}
Attributes : {System.Management.Automation.ValidateSet
Attribute, __AllParameterSets, System.Man
agement.Automation.ValidateNotNullOrEmpty
Attribute}
Notice that this also tells you if the parameter has an alias, is positional, etc. That parameter has a set of Attributes:
PS> $p.Attributes |ft Typeid
TypeId
——
System.Management.Automation.ValidateSetAttribute
System.Management.Automation.ParameterAttribute
System.Management.Automation.ValidateNotNullOrEmptyAttribute
The ValidateSetAttribute has the list of valid strings for this Parameter:
PS> ($p.Attributes|? {$_.Typeid -match “ValidateSetAttribute” }).ValidValues
unicode
utf7
utf8
utf32
ascii
bigendianunicode
default
oem
And there you have it. A little chewy yes but I don’t expect end-users to ever care about this but system programmers and tool vendors will.
Enjoy!
Jeffrey Snover [MSFT]
Windows PowerShell Architect
PSMDTAG:FAQ: Is there a programmatic way to get valid string values for a parameter?
PSMDTAG:PHILOSOPHY: Use Attributes instead of code for validating parameters.
PSMDTAG:INTERNAL: walk through of the Parameter data for cmdlets
Great article and exactly what I needed today - I wanted to extract the valid values of hash algorithms supported by Get-Filehash programmatically so my script would alsways use the right values without me having to hard code them.
One problem I had using your code was that I had to use ValidateSet instead of ValidateSetAttribute for the final extraction of ValidValues. here's my code:
#Grab the "Get-Filehash -Algorithm" parameter object
$getFileHashParams = (Get-Command Get-Filehash).Parametersets[0].parameters |?{$_.name -eq "Algorithm"}
#Grab the valid values for the parameter "Get-Filehash -Algorithm" from its ValidateSet
$algorithms = @(($getFileHashParams.Attributes|? {$_.TypeId -match "ValidateSet"...
Great article and exactly what I needed today - I wanted to extract the valid values of hash algorithms supported by Get-Filehash programmatically so my script would alsways use the right values without me having to hard code them.
One problem I had i nyour code was that I have to use ValidateSet instead of ValidateSetAttribute for the final extraction of ValidValues. here's my code:
#Grab the "Get-Filehash -Algorithm" parameter object
$getFileHashParams = (Get-Command Get-Filehash).Parametersets[0].parameters |?{$_.name -eq "Algorithm"}
#Grab the valid values for the parameter "Get-Filehash -Algorithm" from its ValidateSet
$algorithms = @(($getFileHashParams.Attributes|? {$_.TypeId -match "ValidateSet"...