Programmatic way to get valid string values for a parameter

Programmatic way to get valid string values for a parameter

Rate This
  • Comments 4

<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

  1. 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?)
  2. 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

Leave a Comment
  • Please add 1 and 8 and type the answer here:
  • Post
  • It's great to have this info available for someone like me who is writing a book about cmdlets which are in development and the docs aren't even done yet.  :)

  • I am trying to use this to retrieve all the valid values for the -role parameter for the get-help command. I am just using this as an example. Should your code work for this because i cannot get it to. I get as far as the penultimate cmd and the final one returns a blank line.

    Thank you

    PS I know i can use values like *mailbox* and *um* but i wud like to see how to find these out for myself without having to rely on generous bloggers with inside knowledge :-)

  • This seems not to work any more with PowerShell v3. However, you could use a statement like "($p.Attributes |? { $_ -is [System.Management.Automation.ValidateSetAttribute] }).ValidValues;" instead to achieve the same result. See d-fens.ch/.../programmatic-way-to-get-valid-values-for-a-cmdlet-parameter for a longer explanation.

  • I missed this blog post (my bad), but here's how I do it. Beginning in PS 3.0, you don't need the Foreach because Windows PowerShell automatically looks for a property value on each object if it doesn't find it on the object collection.

    PS 3.0 - 4.0:

    $p.Attributes.ValidValues

    PS 2.0 - 4.0:

    $p.Attributes | foreach {$_.ValidValues}

Page 1 of 1 (4 items)