about_Enum
Short description
The enum
statement declares an enumeration. An enumeration is a
distinct type that consists of a set of named labels called the enumerator
list.
Long description
The enum
statement allows you to create a strongly typed set of labels. You
can use that enumeration in the code without having to parse or check for
spelling errors.
Enumerations are internally represented as integral value types with a starting
value of zero. PowerShell enumerations use System.Int32 ([int]
) as the
underlying type. By default, PowerShell assigns the first label in the list the
value zero. By default, PowerShell assigns the remaining labels with
consecutive integers.
In the definition, you can give labels any integer value. Labels with no value assigned take the next integer value.
Syntax
Enumerations use the following syntaxes:
Integer enumeration definition syntax
[[<attribute>]...] enum <enum-name> {
<label> [= <int-value>]
...
}
Flag enumeration definition syntax
[[<attribute>]...] [Flag()] enum <enum-name>[ : <underlying-type-name>] {
<label 0> [= 1]
<label 1> [= 2]
<label 2> [= 4]
<label 3> [= 8]
...
...
}
Enumeration access syntax
[<enum-name>]::<label>
Examples
Example 1 - Minimal enumeration
The following code block defines the MarkdownUnorderedListCharacter enumeration with three labels. It doesn't assign explicit values to any label.
enum MarkdownUnorderedListCharacter {
Asterisk
Dash
Plus
}
The next code block shows how both integer and string values behave when cast to the enumeration type.
$ValuesToConvert = @(0, 'Asterisk', 1, 'Dash', 2, 'Plus')
foreach ($Value in $ValuesToConvert) {
[MarkdownUnorderedListCharacter]$EnumValue = $Value
[pscustomobject]@{
AssignedValue = $Value
Enumeration = $EnumValue
AreEqual = $Value -eq $EnumValue
}
}
AssignedValue Enumeration AreEqual
------------- ----------- --------
0 Asterisk True
Asterisk Asterisk True
1 Dash True
Dash Dash True
2 Plus True
Plus Plus True
Casting integers that are equal to the value of an enumeration returns that enumeration. Casting strings that are the same as the label of an enumeration returns that enumeration.
Example 2 - Explicit and synonym enumeration values
The following example shows an enumeration of objects that correlate to media
files. The definition assigns explicit values to the underlying values of
music
, picture
, video
. Labels immediately following an explicit
assignment get the next integer value. You can create synonyms by assigning the
same value to another label; see the constructed values for: ogg
, oga
,
mogg
, or jpg
, jpeg
, or mpg
, mpeg
.
enum MediaTypes {
unknown
music = 10
mp3
aac
ogg = 15
oga = 15
mogg = 15
picture = 20
jpg
jpeg = 21
png
video = 40
mpg
mpeg = 41
avi
m4v
}
The GetEnumNames()
method returns the list of the labels for the enumeration.
[MediaTypes].GetEnumNames()
unknown
music
mp3
aac
ogg
oga
mogg
picture
jpg
jpeg
png
video
mpg
mpeg
avi
m4v
The GetEnumValues()
method returns the list of the values for the
enumeration.
[MediaTypes].GetEnumValues()
unknown
music
mp3
aac
oga
oga
oga
picture
jpeg
jpeg
png
video
mpeg
mpeg
avi
m4v
Note
GetEnumNames()
and GetEnumValues()
seem to return the same results; a
list of named values. However, internally, GetEnumValues()
enumerates the
values, then maps values into names. Read the list carefully and you'll
notice that ogg
, oga
, and mogg
appear in the output of
GetEnumNames()
, but the output of GetEnumValues()
only shows oga
. The
same thing happens for jpg
, jpeg
, and mpg
, mpeg
. The name PowerShell
returns for synonym values isn't deterministic.
You can use the GetEnumName()
method to get a name associated with a specific
value. If there are multiple names associated with a value, the method returns
the alphabetically first name.
[MediaTypes].GetEnumName(15)
oga
The following example shows how to map each name to its value.
[MediaTypes].GetEnumNames() | ForEach-Object {
[pscustomobject]@{
Name = $_
Value = [int]([MediaTypes]::$_)
}
}
Name Value
---- -----
unknown 0
music 10
mp3 11
aac 12
ogg 15
oga 15
mogg 15
picture 20
jpg 21
jpeg 21
png 22
video 40
mpg 41
mpeg 41
avi 42
m4v 43
You can specify a single enum value by its label with the syntax
[<enum-name>]::<label>
.
[MediaTypes]::png
[MediaTypes]::png -eq 22
png
True
Example 3 - Enumeration as flags
The following code block creates the FileAttributes enumeration as a set of bit flags. The value for each label is double the value of the prior label.
[Flags()] enum FileAttributes {
Archive = 1
Compressed = 2
Device = 4
Directory = 8
Encrypted = 16
Hidden = 32
}
[FileAttributes]$file1 = [FileAttributes]::Archive
[FileAttributes]$file1 += [FileAttributes]::Compressed
[FileAttributes]$file1 += [FileAttributes]::Device
"file1 attributes are: $file1"
[FileAttributes]$file2 = [FileAttributes]28 ## => 16 + 8 + 4
"file2 attributes are: $file2"
file1 attributes are: Archive, Compressed, Device
file2 attributes are: Device, Directory, Encrypted
To test whether a specific flag is set, you can use the binary comparison
operator -band
. This example tests for the Device and the Archive
attributes in the value of $file2
.
PS > ($file2 -band [FileAttributes]::Device) -eq [FileAttributes]::Device
True
PS > ($file2 -band [FileAttributes]::Archive) -eq [FileAttributes]::Archive
False
You can also use the HasFlag()
method to test whether a specific flag is set.
This example tests for the Device and Hidden attributes in the value of
$file1
.
PS > $file1.HasFlag([FileAttributes]::Device)
True
PS > $file1.HasFlag([FileAttributes]::Hidden)
False
Example 4 - Enumeration as a parameter
In the following example, the function ConvertTo-LineEndingRegex
defines the
InputObject parameter with the type EndOfLine.
enum EndOfLine {
CR = 1
LF = 2
CRLF = 3
}
function ConvertTo-LineEndingRegex {
[CmdletBinding()]
param (
[Parameter(ValueFromPipeline)]
[EndOfLine[]]$InputObject
)
process {
switch ($InputObject) {
CR { '\r' }
LF { '\n' }
CRLF { '\r\n' }
}
}
}
[EndOfLine]::CR | ConvertTo-LineEndingRegex
'CRLF' | ConvertTo-LineEndingRegex
ConvertTo-LineEndingRegex 2
\r
\r\n
\n
In the example, the first statement calling ConvertTo-LineEndingRegex
passes
the enumeration value for CR
. The second statement passes the string
'CRLF'
, which is cast to a LineEnding. The third statement specifies the
value 2
for the parameter, which maps to the LF
label.
You can see the argument completion options by typing the following text into your PowerShell prompt:
ConvertTo-LineEndingRegex -InputObject <Tab>
When you specify an invalid label name or numerical value for the parameter, the function raises an error.
ConvertTo-LineEndingRegex -InputObject 0
ConvertTo-LineEndingRegex : Cannot process argument transformation on
parameter 'InputObject'. Cannot convert value "0" to type "EndOfLine[]".
Error: "Cannot convert value "0" to type "EndOfLine" due to enumeration
values that are not valid. Specify one of the following enumeration values
and try again. The possible enumeration values are "CR,LF,CRLF"."
At line:1 char:40
+ ConvertTo-LineEndingRegex -InputObject 0
+ ~
+ CategoryInfo : InvalidData: (:) [ConvertTo-LineEndingRegex]
, ParameterBindingArgumentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Convert
To-LineEndingRegex
Enumeration methods
The following list includes useful methods available to enumerations in PowerShell and how to use them.
Format
The Format()
static method returns the formatted string output for a given
enumeration type, enumeration value, and format string. The output is the same
as calling the ToString method on the value with the specified format
string.
You can use the static method on the System.Enum base class type or a specific enumeration type.
[System.Enum]::format([<enum-name>], <value>, <format-string>)
[<enum-name>]::format([<enum-name>], <value>, <format-string>)
The valid format strings are G
or g
, D
or d
, X
or x
, and F
or
f
. For more information, see Enumeration Format Strings.
The following example uses each of the supported enumeration format strings to convert each value of the TaskState enumeration to its string representations.
enum TaskState {
ToDo
Doing
Done
}
# String format template for the statements
$Statement = "[System.Enum]::Format([TaskState], {0}, '{1}')"
foreach ($Format in @('G', 'D', 'X', 'F')) {
$StatementToDo = $Statement -f 0, $Format
$StatementDoing = $Statement -f "([TaskState]'Doing')", $Format
$StatementDone = $Statement -f '[TaskState]::Done', $Format
$FormattedToDo = [System.Enum]::Format(
[TaskState], 0, $Format
)
$FormattedDoing = [System.Enum]::Format(
[TaskState], ([TaskState]'Doing'), $Format
)
$FormattedDone = [System.Enum]::Format(
[TaskState], [TaskState]::Done, $Format
)
"{0,-62} => {1}" -f $StatementToDo, $FormattedToDo
"{0,-62} => {1}" -f $StatementDoing, $FormattedDoing
"{0,-62} => {1}" -f $StatementDone, $FormattedDone
}
[System.Enum]::Format([TaskState], 0, 'G') => ToDo
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'G') => Doing
[System.Enum]::Format([TaskState], [TaskState]::Done, 'G') => Done
[System.Enum]::Format([TaskState], 0, 'D') => 0
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'D') => 1
[System.Enum]::Format([TaskState], [TaskState]::Done, 'D') => 2
[System.Enum]::Format([TaskState], 0, 'X') => 00000000
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'X') => 00000001
[System.Enum]::Format([TaskState], [TaskState]::Done, 'X') => 00000002
[System.Enum]::Format([TaskState], 0, 'F') => ToDo
[System.Enum]::Format([TaskState], ([TaskState]'Doing'), 'F') => Doing
[System.Enum]::Format([TaskState], [TaskState]::Done, 'F') => Done
GetEnumName
The GetEnumName()
reflection method returns the name for a specific
enumeration value. The input value must be a valid underlying type for an
enumeration, like an integer, or an enumeration value. If there are multiple
names associated with a value, the method returns the alphabetically first
name.
[<enum-name>].GetEnumName(<value>)
enum GateState {
Unknown
Open
Opening
Closing
Closed
}
foreach ($Value in 0..4) {
[pscustomobject]@{
IntegerValue = $Value
EnumName = [GateState].GetEnumName($Value)
}
}
IntegerValue EnumName
------------ --------
0 Unknown
1 Open
2 Opening
3 Closing
4 Closed
GetEnumNames
The GetEnumNames()
reflection method returns the names for every enumeration
value as strings. The output includes synonyms.
[<enum-name>].GetEnumNames()
enum Season {
Unknown
Spring
Summer
Autumn
Winter
Fall = 3
}
[Season].GetEnumNames()
Unknown
Spring
Summer
Fall
Autumn
Winter
GetEnumUnderlyingType
The GetEnumUnderlyingType()
reflection method returns the underlying type for
the enumeration values.
[<enum-name>].GetEnumUnderlyingType()
enum IntBasedEnum {
Zero
One
Two
}
$NonIntEnum = [System.Management.Automation.Tracing.PowerShellTraceKeywords]
foreach ($EnumType in @([IntBasedEnum], $NonIntEnum)) {
[pscustomobject]@{
EnumType = $EnumType
ValueType = $EnumType.GetEnumUnderlyingType()
}
}
EnumType ValueType
-------- ---------
IntBasedEnum System.Int32
System.Management.Automation.Tracing.PowerShellTraceKeywords System.UInt64
GetEnumValues
The GetEnumValues()
reflection method returns every defined value for the
enumeration.
[<enum-name>].GetEnumValues()
enum Season {
Unknown
Spring
Summer
Autumn
Winter
Fall = 3
}
[Season].GetEnumValues()
Unknown
Spring
Summer
Autumn
Autumn
Winter
HasFlag
The HasFlag
instance method determines whether a bit flag is set for a flag
enumeration value. Using this method is shorter and easier to read than doing a
binary comparison and equivalency check.
<enum-value>.HasFlag(<enum-flag-value>)
The following example defines the ModuleFeatures flag enumeration and shows
which flags the value 39
has.
[Flags()] enum ModuleFeatures {
Commands = 1
Classes = 2
Enums = 4
Types = 8
Formats = 16
Variables = 32
}
$Features = [ModuleFeatures]39
foreach ($Feature in [ModuleFeatures].GetEnumValues()) {
"Has flag {0,-12}: {1}" -f "'$Feature'", ($Features.HasFlag($Feature))
}
Has flag 'Commands' : True
Has flag 'Classes' : True
Has flag 'Enums' : True
Has flag 'Types' : False
Has flag 'Formats' : False
Has flag 'Variables' : True
IsDefined
The IsDefined()
static method returns $true
if the input value is defined
for the enumeration and otherwise $false
. Use this method to check whether a
value is valid for an enumeration without needing to handle invalid argument
errors.
You can use the static method on the System.Enum base class type or a specific enumeration type.
[System.Enum]::IsDefined([<enum-name>], <value>)
[<enum-name>]::IsDefined([<enum-name>], <value>)
enum Season {
Unknown
Spring
Summer
Autumn
Winter
Fall = 3
}
foreach ($Value in 0..5) {
$IsValid = [Season]::IsDefined([Season], $Value)
$EnumValue = if ($IsValid) { [Season]$Value }
[pscustomobject] @{
InputValue = $Value
IsValid = $IsValid
EnumValue = $EnumValue
}
}
InputValue IsValid EnumValue
---------- ------- ---------
0 True Unknown
1 True Spring
2 True Summer
3 True Autumn
4 True Winter
5 False
ToString
The ToString()
instance method returns the label for an enumeration value.
This method is also the default view for how an enumeration value displays as
output. Optionally, you can specify a format string to control how the value
displays. For more information about formatting, see
Formatting enumeration values.
Note
For enumerations that define synonyms for a specific value, don't write code
that depends on the output of ToString()
. The method can return any valid
name for the value.
<enum-value>.ToString([<format-string>])
The following example defines the Shade enumeration with Gray
as a
synonym for Grey
. It then outputs objects that show the actual enum value,
the enum as a string, and the enum as an integer.
enum Shade {
White
Grey
Gray = 1
Black
}
[Shade].GetEnumValues() | Foreach-Object -Process {
[pscustomobject]@{
EnumValue = $_
StringValue = $_.ToString()
IntegerValue = [int]$_
}
}
numValue StringValue IntegerValue
--------- ----------- ------------
White White 0
Grey Grey 1
Grey Grey 1
Black Black 2
Enumeration value synonyms
You can define enumerations that give different names to the same integer value. When you do, the names that point to the same underlying value are called synonyms. Enumerations with synonyms enable users to specify different names for the same value.
When you define an enumeration with synonyms, don't write code that depends on a synonym value converting to a specific name. You can reliably write code that converts a synonym string to the enumeration value. When working with the enumeration value itself, always compare it as an enumeration value or its underlying type instead of as a string.
The following code block defines the Shade enumeration with Grey
and
Gray
as synonyms.
enum Shade {
White
Grey
Gray = 1
Black
}
[Shade]'Grey' -eq [Shade]::Gray
[Shade]::Grey -eq 1
[Shade]'Gray' -eq 1
True
True
True
Enumerations as flags
One common use of an enumeration is to represent a set of mutually exclusive values. For example, an ArrivalStatus instance can have a value of Early, OnTime, or Late. It makes no sense for the value of an ArrivalStatus instance to reflect more than one enumeration constant.
In other cases, however, the value of an enumeration object can include multiple enumeration members, and each member represents a bit field in the enumeration value. You can use the FlagsAttribute to indicate that the enumeration consists of bit fields as flags that users can combine.
For enumerations as flags to work properly, you must set each label's integer value to a power of two. If you don't specify a value for a label, PowerShell sets the value to one higher than the previous label.
You can define values for commonly used flag combinations to make it easier for users to specify a set of flags at once. The name for the value should be the combined names of the flags. The integer value should be the sum of the flag values.
To determine whether a specific flag is set for a value, use the HasFlag()
method on the value or use the binary comparison operator -band
.
For a sample showing how to use flag enumerations and check whether a flag is set, see Example 3.
Enumerations as parameters
You can define cmdlet parameters that use an enum as their type. When you specify an enum as the type for a parameter, users get automatic completion for and validation of the parameter's value. The argument completion suggests the list of valid labels for the enum.
When a parameter has an enum as its type, you can specify any of:
- An enumeration, like
[<EnumType>]::<Label>
- The label for an enumeration as a string
- The numerical value of an enumeration
For a sample showing the behavior of an enumeration-typed parameter, see Example 4.
Formatting enumeration values
You can convert enumeration values to their string representations by calling the static Format method, as well as the overloads of the instance ToString method. You can use a format string to control the precise way in which an enumeration value is represented as a string. For more information, see Enumeration Format Strings.
The following example uses each of the supported enumeration format strings
(G
or g
, D
or d
, X
or x
, and F
or f
) to convert each member of
the TaskState enumeration to its string representations.
enum TaskState {
ToDo
Doing
Done
}
[TaskState].GetEnumValues() | ForEach-Object {
[pscustomobject]@{
"ToString('G')" = $_.ToString('G')
"ToString('D')" = $_.ToString('D')
"ToString('X')" = $_.ToString('X')
"ToString('F')" = $_.ToString('F')
}
}
ToString('G') ToString('D') ToString('X') ToString('F')
------------- ------------- ------------- -------------
ToDo 0 00000000 ToDo
Doing 1 00000001 Doing
Done 2 00000002 Done
The following example uses the format strings for values of a flag enumeration.
[Flags()] enum FlagEnum {
A = 1
B = 2
C = 4
}
$FlagValues = @(
[FlagEnum]::A # 1
[FlagEnum]::B # 2
[FlagEnum]::A + [FlagEnum]::B # 3
[FlagEnum]::C # 4
[FlagEnum]::C + [FlagEnum]::A # 5
[FlagEnum]::C + [FlagEnum]::B # 6
[FlagEnum]::C + [FlagEnum]::A + [FlagEnum]::B # 7
[FlagEnum]::C + [FlagEnum]::C # 8
)
foreach ($Value in $FlagValues) {
[pscustomobject]@{
"ToString('G')" = $Value.ToString('G')
"ToString('D')" = $Value.ToString('D')
"ToString('X')" = $Value.ToString('X')
"ToString('F')" = $Value.ToString('F')
}
}
ToString('G') ToString('D') ToString('X') ToString('F')
------------- ------------- ------------- -------------
A 1 00000001 A
B 2 00000002 B
A, B 3 00000003 A, B
C 4 00000004 C
A, C 5 00000005 A, C
B, C 6 00000006 B, C
A, B, C 7 00000007 A, B, C
8 8 00000008 8
Notice that for flags enumerations, the G
and F
format strings display the
list of set flags for the value delimited with commas. The last value, 8
,
doesn't list any flags because it's not actually a valid flag set. You can't
combine the enumeration flags to get a sum of 8
without duplicating at least
one flag.
Defining extension methods with Update-TypeData
You can't define methods in the declaration for an enumeration. To extend the
functionality of an enumeration, you can use the Update-TypeData cmdlet
to define ScriptMethod
members for the enumeration.
The following example uses the Update-TypeData
cmdlet to add a GetFlags()
method to the FileAttributes flag enumeration. It returns an array of the
flags set for the value.
[Flags()] enum FileAttributes {
Archive = 1
Compressed = 2
Device = 4
Directory = 8
Encrypted = 16
Hidden = 32
}
$MemberDefinition = @{
TypeName = 'FileAttributes'
MemberName = 'GetFlags'
MemberType = 'ScriptMethod'
Value = {
foreach ($Flag in $this.GetType().GetEnumValues()) {
if ($this.HasFlag($Flag)) { $Flag }
}
}
}
Update-TypeData @MemberDefinition
$File = [FileAttributes]28
$File.GetFlags()
Device
Directory
Encrypted
Exporting enumerations with type accelerators
By default, PowerShell modules don't automatically export classes and
enumerations defined in PowerShell. The custom types aren't available outside
of the module without calling a using module
statement.
However, if a module adds type accelerators, those type accelerators are immediately available in the session after users import the module.
Note
Adding type accelerators to the session uses an internal (not public) API. Using this API may cause conflicts. The pattern described below throws an error if a type accelerator with the same name already exists when you import the module. It also removes the type accelerators when you remove the module from the session.
This pattern ensures that the types are available in a session. It doesn't
affect IntelliSense or completion when authoring a script file in VS Code.
To get IntelliSense and completion suggestions for custom types in VS Code,
you need to add a using module
statement to the top of the script.
The following pattern shows how you can register PowerShell classes and
enumerations as type accelerators in a module. Add the snippet to the root
script module after any type definitions. Make sure the $ExportableTypes
variable contains each of the types you want to make available to users when
they import the module. The other code doesn't require any editing.
# Define the types to export with type accelerators.
$ExportableTypes =@(
[DefinedTypeName]
)
# Get the internal TypeAccelerators class to use its static methods.
$TypeAcceleratorsClass = [psobject].Assembly.GetType(
'System.Management.Automation.TypeAccelerators'
)
# Ensure none of the types would clobber an existing type accelerator.
# If a type accelerator with the same name exists, throw an exception.
$ExistingTypeAccelerators = $TypeAcceleratorsClass::Get
foreach ($Type in $ExportableTypes) {
if ($Type.FullName -in $ExistingTypeAccelerators.Keys) {
$Message = @(
"Unable to register type accelerator '$($Type.FullName)'"
'Accelerator already exists.'
) -join ' - '
throw [System.Management.Automation.ErrorRecord]::new(
[System.InvalidOperationException]::new($Message),
'TypeAcceleratorAlreadyExists',
[System.Management.Automation.ErrorCategory]::InvalidOperation,
$Type.FullName
)
}
}
# Add type accelerators for every exportable type.
foreach ($Type in $ExportableTypes) {
$TypeAcceleratorsClass::Add($Type.FullName, $Type)
}
# Remove type accelerators when the module is removed.
$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = {
foreach($Type in $ExportableTypes) {
$TypeAcceleratorsClass::Remove($Type.FullName)
}
}.GetNewClosure()
When users import the module, any types added to the type accelerators for the session are immediately available for IntelliSense and completion. When the module is removed, so are the type accelerators.
Manually importing enumerations from a PowerShell module
Import-Module
and the #requires
statement only import the module functions,
aliases, and variables, as defined by the module. Enumerations aren't imported.
If a module defines classes and enumerations but doesn't add type accelerators
for those types, use a using module
statement to import them.
The using module
statement imports classes and enumerations from the root
module (ModuleToProcess
) of a script module or binary module. It doesn't
consistently import classes defined in nested modules or classes defined in
scripts that are dot-sourced into the root module. Define classes that you want
to be available to users outside of the module directly in the root module.
For more information about the using
statement, see about_Using.
Loading newly changed code during development
During development of a script module, it's common to make changes to the code
then load the new version of the module using Import-Module
with the
Force parameter. This works for changes to functions in the root module
only. Import-Module
doesn't reload any nested modules. Also, there's no way
to load any updated classes.
To ensure that you're running the latest version, you must start a new session.
Classes and enumerations defined in PowerShell and imported with a using
statement can't be unloaded.
Another common development practice is to separate your code into different
files. If you have function in one file that use enumerations defined in
another module, you should using the using module
statement to ensure that
the functions have the enumeration definitions that are needed.
Limitations
You can't define enumerations in Windows PowerShell with a specific underlying type. You can only define enumerations with an underlying type of System.Int32.
Workaround: Use PowerShell 6.2 or newer. Starting in PowerShell 6.2, you can define enumerations with a specific underlying type.
You can't decorate enumeration values defined in PowerShell with attributes. You can only decorate the enumeration declaration itself, as with the FlagsAttribute for defining an enumeration as a set of bit flags.
Workaround: None
You can't define methods inside enumeration definitions and PowerShell doesn't support defining [extension methods] like C#.
Workaround: Use the Update-TypeData cmdlet to define
ScriptMethod
members for the enumeration.