Enumerated Types in Windows PowerShell 5.0
- Details
- Written by June Blender
- Last Updated: 13 June 2016
- Created: 05 January 2015
- Hits: 15440
Enums have always been a part of Windows PowerShell, because they’re an important part of the .NET Framework. But they’re about to become even more popular, because changes in Windows PowerShell 5.0 make them very easy to create.
———–
Enumerated types (“enums”) define a set of values, knows as “members” of the enum. You use enums to create a set of valid values and prohibit all other values. In Windows PowerShell, you can use enumerated types just as you use .NET classes. For example, the value of the ExecutionPolicy parameter of the Set-ExecutionPolicy cmdlet has a type of ExecutionPolicy and its Scope parameter has a type of ExecutionPolicyScope.
Set-ExecutionPolicy [-ExecutionPolicy] <ExecutionPolicy> [[-Scope] <ExecutionPolicyScope>] [-Force] [-WhatIf] [-Confirm] [<CommonParameters>]
Both ExecutionPolicy and ExecutionPolicyScope are enums. The enum members are listed and defined on the MSDN page for each enum.
If you try to use a value that is not a member of the enum, you get a very helpful error. The error explains that the value is limited to the enum and lists the valid values. So, a quick way to find the members of an enum is to try a value that is clearly not valid, like good old “foo”.
[ADMIN]: PS C:\ps-test> Set-ExecutionPolicy -ExecutionPolicy foo Set-ExecutionPolicy : Cannot bind parameter 'ExecutionPolicy'. Cannot convert value "foo" to type "Microsoft.PowerShell.ExecutionPolicy". Error: "Unable to match the identifier name foo to a valid enumerator name. Specify one of the following enumerator names and try again: Unrestricted, RemoteSigned, AllSigned, Restricted, Default, Bypass, Undefined" At line:1 char:38 + Set-ExecutionPolicy -ExecutionPolicy foo + ~~~ + CategoryInfo : InvalidArgument: (:) [Set-ExecutionPolicy], ParameterBindingException + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand
It’s easy to use enums. This excellent article from the TechNet Library explains it well. And, Windows PowerShell has let you define your own enums since 1.0, but it was a bit tricky. Not any more!
Create an enum
In Windows PowerShell 5.0, the enum keyword makes it much easier. Here’s a WineSweetness enum that I created for my Wine class.
enum WineSweetness { VeryDry Dry Moderate Sweet VerySweet } |
I use it to limit parameter values, much like ValidateSet, but unlike ValidateSet, once it’s defined in my session, script, or module, I can use it repeatedly without redefining it. In this example, I use it to limit the values of the Sweetness property of instances of my Wine class.
class Wine { #Properties [String]$Name [WineSweetness]$Sweetness ... } |
I can also use it functions, such as my Get-Wine function, without redefining it.
function Get-Wine { Param ( [parameter(Mandatory = $false)] [WineSweetness] $SweetnessValue, ... } |
Enum syntax
The enum syntax is so easy. Just note that the list is NOT comma-separated. If you prefer to list the values on a single line, use semi-colons.
enum { Value1 [Value2...] } |
-or-
enum { Value1; [Value2...;] } |
The value names cannot include spaces or special characters, although an underscore (_) is permitted. Enclosing a names with spaces in quotation marks or curly braces doesn’t help. If you include a space, Windows PowerShell thinks it’s an expression, which is permitted.
enum WineSweetness { VeryDry Dry Moderate Sweet Very Sweet # <--- No spaces } Very : The term 'Very' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:1 char:5 + Very Sweet + ~~~~ + CategoryInfo : ObjectNotFound: (Very:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
The values cannot be numbers and the first character of a value name cannot be a number. The ‘ missing closing “}” ‘ error is not very helpful, so watch out for this one.
PS C:\> enum WineSweetness { VeryDry Dry 3 # <------ No numbers Sweet VerySweet } At line:4 char:8 + Dry + ~ Missing closing '}' in statement block or type definition. At line:8 char:1 + } + ~ Unexpected token '}' in expression or statement. + CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException + FullyQualifiedErrorId : MissingEndCurlyBrace
Enums have integer values
Every enum value has a corresponding integer value. When you create an enum in Windows PowerShell (by using the Add-Type cmdlet or the enum keyword), the parser assigns a default integer value to each enum value. These default integer values begin with zero and increase by 1. The values are assigned in the order they are listed in the enum declaration.
For example, when I created my WineSweetness enum, Windows PowerShell assigned the values 0 – 4 to the enum values.
enum WineSweetness { VeryDry Dry Moderate Sweet VerySweet } |
To find the values in any enum, call the GetValues static method of the System.Enum type:
PS C:\> [System.Enum]::GetValues([WineSweetness]) VeryDry Dry Moderate Sweet VerySweet
To find the underlying integer value of each enum value, cast the enum value to an integer (thanks to Keith Babinec for this trick).
PS C:\> [System.Enum]::GetValues([WineSweetness]) | foreach { [int]$_ } 0 1 2 3 4
Let’s put them together. This command creates a custom object (I love PSCustomObject!) with the names and integer value of each enum value.
PS C:\> [System.Enum]::GetValues([WineSweetness]) | foreach { [PSCustomObject]@{ValueName = $_; IntValue = [int]$_ } } ValueName IntValue --------- -------- VeryDry 0 Dry 1 Moderate 2 Sweet 3 VerySweet 4
You can also assign integer values, and expressions that return an integer value, to your enum values. The values that you assign override the default zero-based values. All enum values are constants, so you can’t change them after you assign them.
PS C:\> enum WineSweetness { Sweet = 4 VeryDry = 2 * 4 + 2 Moderate = 6 VerySweet = 2 Dry = 8 } [System.Enum]::GetValues([WineSweetness]) | foreach {[PSCustomObject]@{ValueName = $_; IntValue = [int]$_} } ValueName IntValue --------- -------- VerySweet 2 Sweet 4 Moderate 6 Dry 8 VeryDry 10
Using an enum
When you use an enum, you can specify either a value name or its integer value.
enum WineSweetness { VeryDry = 1 Dry = 2 Moderate = 3 Sweet = 4 VerySweet = 5 } |
I’ll create an instance of my Wine class and set its Sweetness property, which has a type of WineSweetness, to VeryDry (my personal favorite).
PS C:\>$PSWine = [Wine]::new("PSCabernet") PS C:\>$PSWine.Sweetness = VeryDry
I can use the dot method to get the string representation of the Sweetness property value:
PS C:\> $PSWine.Sweetness VeryDry
Or, use the Value__ (that’s 2 underscores) property of all enum values to get its integer value.
PS C:\> $PSWine.Sweetness.value__ 1
If I try to change the value of the Sweetness property to a value that’s not in the enum, I get that awesome error that lists the valid values.
PS C:\ps-test> $PSWine.Sweetness = "TooSweet" Exception setting "Sweetness": "Cannot convert value "TooSweet" to type "WineSweetness". Error: "Unable to match the identifier name TooSweet to a valid enumerator name. Specify one of the following enumerator names and try again: VeryDry, Dry, Moderate, Sweet, VerySweet"" At line:1 char:1 + $PSWine.Sweetness = "TooSweet" + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], SetValueInvocationException + FullyQualifiedErrorId : ExceptionWhenSetting
Just so I use a valid value, I can assign either a string or a integer value.
PS C:\> $PSWine.Sweetness = Dry PS C:\> $PSWine.Sweetness Dry PS C:\> $PSWine.Sweetness = 3 PS C:\> $PSWine.Sweetness Moderate
When you sort objects by an enumerated property value, the Sort-Object cmdlet sorts by integer value. For example, I have some wines in a $myWines variable.
PS C:\ps-test> $myWines Name : Great Duck Winery : Escalante Winery Year : 2003 isSparkling : True Color : White Sweetness : VerySweet Description : Rich and magnificent Rating : {98, 97} Name : PSCabernet Winery : Chateau Snover Year : 2006 isSparkling : False Color : Red Sweetness : VeryDry Description : Pithy Rating : {96} Name : Shiraz Winery : SAPIEN Vineyards Year : 1990 isSparkling : False Color : Red Sweetness : Dry Description : Bold and innovative Rating : {100}
When I sort them by the value of the Sweetness property, I get them in ascending integer value order. I used a calculated property to add the integer value to the table.
PS C:\ps-test> $mywines | Sort-Object -Property Sweetness | Format-Table -Property Name, ` Sweetness, ` @{Label="IntSweet"; Expression={$_.Sweetness.Value__}} -AutoSize Name Sweetness IntSweet ---- --------- -------- PSWine VeryDry 1 Shiraz Dry 2 Great Duck VerySweet 5
The introduction of the enum keyword has really made enumerated types available to everyone. Yet another tool for your Windows PowerShell toolbox.
June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.
[Update: The original article referred to “enums” as “enumerators” when, in fact, they are “enumerated types.” By contrast, enumerators allow you to process items one at a time. Many thanks to Windows PowerShell MVP Dave Wyatt (@msh_Dave) for the correction.]
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.