66

I am using switch parameters in my PowerShell script in this fashion.

param(
    [switch] $Word,
    [switch] $Excel,
    [switch] $powerpoint,
    [switch] $v2007,
    [switch] $v2010,
    [switch] $x86,
    [switch] $x64,
)

I am trying to figure out any neat way to have it more enum style. As anyone might guess, I would want the user to choose between word, excel and powerpoint. And between x2007 and v2010.

Is there a neat way to get input params enum style?

I am new to PowerShell. So if this sounds like that I don't know something obvious, then please point me to some link where I can read about it.

wonea
  • 4,783
  • 17
  • 86
  • 139
bits
  • 8,110
  • 8
  • 46
  • 55

4 Answers4

115

I would use a ValidateSet parameter attribute instead.

From: about_Functions_Advanced_Parameters

The ValidateSet attribute specifies a set of valid values for a parameter or variable. Windows PowerShell generates an error if a parameter or variable value does not match a value in the set.

Example function:

function test-value
{
    param(
        [Parameter(Position=0)]
        [ValidateSet('word','excel','powerpoint')]
        [System.String]$Application,

        [Parameter(Position=1)]
        [ValidateSet('v2007','v2010')]
        [System.String]$Version
    )


    write-host "Application: $Application"
    write-host "Version: $Version"
}   


PS > test-value -application foo

Output:

test-value : Cannot validate argument on parameter 'Application'. The argument "foo" does not belong to the set "word,excel,powerpoint" specified by the ValidateSet attribute. Supply an argument that is in the set and then try the command again.

Igor Popov
  • 9,795
  • 7
  • 55
  • 68
Shay Levy
  • 121,444
  • 32
  • 184
  • 206
  • This approach forces you into using advanced functions which isn't *always* desirable. You also don't get any form of auto-completion on the enum values. OTOH you don't have to put the enum evaluation within parens e.g. `[MyEnum]::A`. So, a mixed bag I guess. :-) – Keith Hill Sep 17 '10 at 21:59
  • Thanks Keith. On the other hand the function needs to implement various parameter checks to find if more than one switch params was specified. BTW, aren't we all using PowerShell v2 :) – Shay Levy Sep 18 '10 at 15:37
  • Keith, you get tab expansion on ValidateSet if you use PowerTab... just sayin. ;) – JasonMArcher Sep 28 '10 at 03:27
  • 3
    You do get tab expansion for sets, now (testing in Windows 8.1, in both Powershell 3.0 & 4.0, but not 2.0) – bdukes Nov 01 '13 at 15:16
11

You can use the ValidateSet attribute:

function My-Func
{
    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [ValidateSet('Word', 'Excel', 'PowerPoint', 'v2007', 'v2010', 'x86', 'x64')]
        [String]$MyParam
    )

    Write-Host "Performing action for $MyParam"
}

My-Func -MyParam 'Word'
My-Func -MyParam 'v2007'
My-Func -MyParam 'SomeVal'

Output:

Performing action for Word
Performing action for v2007
My-Func : Cannot validate argument on parameter 'MyParam'. The argument "SomeVal" does not belong to the set "Word,Excel,PowerPoint,v2007,v2010,x86,x64" specified by the ValidateSet attribute. Supply an argument that is in the
 set and then try the command again.
At C:\Users\George\Documents\PowerShell V2\ValidateSetTest.ps1:15 char:17
+ My-Func -MyParam <<<<  'SomeVal'
    + CategoryInfo          : InvalidData: (:) [My-Func], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,My-Func
George Howarth
  • 2,767
  • 20
  • 18
10

This blog post by the PowerShell team defines how to do this in PowerShell 1.0. In PowerShell 2.0 you can use Add-Type like so:

C:\PS> Add-Type -TypeDefinition @'
>> public enum MyEnum {
>> A,
>> B,
>> C,
>> D
>> }
>> '@
>>

Update: Here's how to use the enum:

C:\PS> function foo([MyEnum]$enum) { $enum }
C:\PS> foo ([MyEnum]::A)
A

You need the parentheses around the argument to parse the argument as a Type. This is required because arguments are treated more or less like strings. Knowing this, you can also pass them enum in a simple string form and powershell will figure it out:

C:\PS> foo A
A
C:\PS> $arg = "B"
C:\PS> foo $arg
B
C:\PS> foo F
error*

error - F is not one of the enumerated values - valid values include A,B,C,D *

x0n
  • 51,312
  • 7
  • 89
  • 111
Keith Hill
  • 194,368
  • 42
  • 353
  • 369
  • 1
    But how can I use these examples of enum for command line "param" purposes? – bits Sep 17 '10 at 14:44
  • an interesting example, but I think it's not really useful in this case. – Jay Bazuzi Sep 19 '10 at 03:07
  • 1
    Yeah having to use the parens kind of bites. OTOH I like the tab-completion - next best thing to a true static verification of the enum value. ValidateSet is certainly a nice feature to have in the language, just too bad PowerShell doesn't use that info to drive tab-completion. BTW if it were just one set of choices, you could use switches like the OP uses - just put each switch in separate parameter set and pick one to be the default (if none are specified). – Keith Hill Sep 19 '10 at 06:06
  • For what it's worth, I think it's worth mentioning that using a real enum allows for Get-Help to provide help to script users without making it an opaque runtime minefield. In the example here, Get-Help would show: SYNTAX foo -enum {A | B | C | D} – bwerks Apr 12 '12 at 07:21
  • 2
    Tab completion for validate set members seems to work now that we're in the future. – stib May 30 '19 at 00:47
5

Since PowerShell 5 you can actually use/create an Enum natively.

enum OS {
    Windows
    Linux
    iOS
}

This is then also visible as its type.

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     OS                                       System.Enum

Maybe a useful link by 4sysops.

To use it in a function, I would either create a separate .psm1 file and add all the enums you need - see my comment which refers to a similiar question - or you can set this enum at the top of your .psm1 file and use in the same file.

For example, I created the file test.psm1 and added this code:

enum OS {
    Windows
    Linux
    iOS
}

function Get-OS {
    param (
        [Parameter(Mandatory)]
        [OS]$os
    )

    Write-Host -Object "The operating system is $os."
    
}

I import the file Import-Module .\test.psm1 and run it:

PS > Get-OS -os Linux
The operating system is Linux.
Alex_P
  • 2,580
  • 3
  • 22
  • 37
  • How would you use this in a powershell script as OP asked? Because as far as I know you can't put the enum in front of the initial param call. – Ivo Merchiers Jan 19 '22 at 10:30
  • @IvoMerchiers, here is a SO question regarding the use of enums in Powershell. https://stackoverflow.com/questions/62511588/enum-parameter-for-powershell-cmdlet/62512656#62512656 – Alex_P Jan 19 '22 at 20:46