Introduction

An Enum type is a data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Enums can be more descriptive rather using just a number.

Enums are used to declare an enumeration, a distinct type that consists of a set of named constants called the enumerator list. 

Accessing Enums

An enum type can be returned from a property of an object or returned from a function. 

For example, $Now is an instance of System.DateTime from the Get-Date cmdlet. DateTime objects have a DayOfWeek property which specifies, the day of the week.

PS C:\> $Now = Get-Date

PS C:\> $Now.DayOfWeek
Monday
 

To see the enum type, use the Get-Member, the definition tell us it is of type System.DayOfWeek

PS C:\> $Now | Get-Member DayOfWeek


   TypeName: System.DateTime

Name         MemberType     Definition                       
----         ----------     ----------                       
DayOfWeek    Property       System.DayOfWeek DayOfWeek {get;}


The enum typename is System.DayOfWeek. The Get-Type cmdlet confirms that the BaseType is an enum (System.Enum).

PS C:\> ($Now.DayOfWeek).GetType()

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



Knowing the enum type name, variables can be also assigned directly.

PS C:\> $DOW=[System.DayOfWeek]::Monday

PS C:\> $DOW
Monday

PS C:\> $DOW.GetType()

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

Within the ISE, Intellisense detects the enum and provides a list to select the enumerator.

Accessing Enumerators

The static method GetNames() is provided by the System.Enum class itself and will give a list of all the enumerator names. 

PS C:\> [System.Enum]::GetNames( [System.DayOfWeek] )
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday 


Accessing Enumerator Values

By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1. To see what value is associated with an enumator, type cast it with a [int].  

PS C:\> $DOW
Monday

PS C:\> [int]$DOW
1

Sunday is 0, Monday is 1 ...

Using Switch on an Enum

When using an enum in a switch construct, a copy of the enumerator name is converted to a string.

[System.DayOfWeek]$DOW=[System.DayOfWeek]::Monday
switch ($DOW)
{
    "Sunday"         {"It's Sunday"; continue } 
    "Monday"        {"It's Monday"; continue } 
    "Tuesday"        {"It's Tuesday"; continue } 
    "Wednesday"  {"It's Wednesday"; continue } 
    "Thursday"      {"It's Thursday"; continue } 
    "Friday"           {"It's Friday"; continue } 
    "Saturday"      {"It's Saturday"; continue } 
}

It's Monday
 


Defining an Enum

PowerShell allows to define a enum using the Add-Type cmdlet. Once the enum type has been added to the console environment, it can not be removed or re-defined? Closing and re-opening the console will remove the enum.

Enums are used to declare an enumeration, a distinct type that consists of a set of named constants called the enumerator list. By default, the first enumerator has the value 0, and the value of each successive enumerator is increased by 1.

Add-Type -TypeDefinition @"
   public enum MyShortDayOfWeek
   {
      Sun,
      Mon,
      Tue,
      Wed,
      Thr,
      Fri,
      Sat
   }
"@

[MyShortDayOfWeek]$Day=[MyShortDayOfWeek]::Tue
$Day  #Show Day

switch ($Day)
{
    "Sun" {"It's Sun"; continue } 
    "Mon" {"It's Mon"; continue } 
    "Tue" {"It's Tue"; continue } 
    "Wed" {"It's Wed"; continue } 
    "Thu" {"It's Thu"; continue } 
    "Fri" {"It's Fri"; continue } 
    "Sat" {"It's Sat"; continue } 
}

Tue
It's Tue

Using the GetType() method confirms that it is a enum.

PS C:\> $Day.GetType()

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


Using Enums With Functions

When a parameter of a function is type cast as an enum, within the ISE, Intellisense will detect that it's an enum and provide a list to select the enumerator.

Functions can have parameters that are typed as enums and functions can have output types that are enums

Here are two sample functions that converts a enumerator to a string and a string to a enumerator. These are wrapper functions for built-in functions and the real purpose is to illustrate how enums can be used as parameters and return types for functions.

Enums as Parameters


In this example, an enum is a parameter and the function returns the string value of enumerator parameter. It uses the ToString() method of the enumerator and returns the result.

The good thing about typecasting the parameter as an enum, it assures only valid values are accepted into the function.

If an attempt to pass value to the function that is not valid member, an error occurs outside of the function. Using enums as parameters makes writing the function easier. It is up to the caller to pass a valid value.


Enums as Return Types


To illustrate an enum as a function output type, a string is the parameter and the function returns the enumerator value of the string parameter. The function uses to the Parse() method of the System.Enum class and returns the result.

In this example, it calls the function with a valid parameter value, shows the return value of the function call and if the result is not null, calls the GetType() method to confirm that is a enum.

In this example, it calls the same function except with an invalid string value. The parse method fails and the catch block catches the error and displays the exception message.

Using Enums Dynamically

So far, in this article, the enum was known upfront at the time of when the coding took place. But how can enums be handled at run-time? That is an advanced topic. In the next section, is a PowerShell function that constructs a switch code block template for an enum to handle all of the enumerator values. The input parameter for the function can be either an enum object, enum name as string, or the enum as a type. To accomplish this, requires the use of the -Is and the -As type operators.

Using Enums with the -Is Type Operator


The -Is operator is a type operator. It returns true or false depending on if the object is the queried type. To check if an object is an enum, check if the object is of the type System.Enum.

This example creates two objects of different types to check if they are enum types. The first is an object of the DayOfWeek enum type and and the second object is of the date-time type which is not an enum. It checks each object to see if they are of the type System.Enum.


The -Is operator will confirm if an object is a certain type throughout it's class inheritance tree. (Class inheritance is beyond the scope of this article). In this example, the -Is operator is utilized for the DayOfWeek enum object for it's entire inheritance class tree, starting with the most specific, the actual [System.DayOfWeek] enum class to the most generic class [System.Object].


So far, the enum type name has been "hard-coded" but at run-time, typically, only a string containing the enum name is available. How to check if a string containing the enum name is a valid enum type name?

In this example, the enum name is stored in the string variable $EnumName. An object is created of the type 
that the string variable $EnumName specifies. The object created is just a enumerator instance that defaults to the first value in the enumerator list, the same type of object used throughout this whole article. The object is used with the -Is type operator to confirm that it is of type System.Enum.


Using Enums with the -As Type Operator


The -As operator is an type operator and returns objects. It attempts to convert objects to the specified type and returns an object of the specified type. It is similar to the New-Object cmdlet but unlike the New-Object cmdlet which constructs new objects, the -As operator works with existing objects.

In a previous section Accessing Enumerator Values, it shown how to type cast an [int] variable to the int value of an enumerator. The -As type operator can perform the same function. In this example, it shows both ways, typecasting and using the -As type operator. It also shows going in both directions; enumerator to value and value (and a string) to an enumerator.




So far, the enum type has been "hard-coded", it always appears as [System.DayOfWeek]. In the previous section Accessing Enumerators, it was shown how to get the names of the enumerators by calling the method GetNames() of the System.Enum class;

PS C:\> [System.Enum]::GetNames( [System.DayOfWeek] )

[System.DayOfWeek] what exactly is that?




[System.DayOfWeek] is a RuntimeType object or more specifically a System.RuntimeType object. How can we get that as a variable to pass to the GetNames() method of the System.Enum class? The short answer is we can't. Nor do we want to, the GetNames() method is expecting a System.Type as a parameter. 

The System.RuntimeType is to a System.Type is like an object is to a class. (A class is the definition of an object and an object is an instance of a class).

Now we're ready to write that function that will take an enumerator object or a string containing the enum name or enum System.Type object as a parameter and generate the PowerShell code for a switch construct code block. 

Function to Generate Select Template for Enum

Some enums have many members, and coding a switch construct can be tedious. This generic function takes the enum name as string, or as an enum object or an enum system.type object and get the names of the enumerators of the enum. It generates a PowerShell code template to be used within your script, if such a switch code block is required.

There are three types of parameters that the function accepts; String, System.Enum, and System.Type. The actual work being performed in the function is associated with only the System.Type parameter because the System.Type object is used directly as a parameter to the GetNames() method. The other two types; string and System.Enum are stepped up, so to speak, to the System.Type parameter and the function is called recursively to accomplish this. 

Function Get-EnumSwitchTemplate
{
    [CmdletBinding()]
    [OutputType([String])]
    Param(
      [Parameter(Mandatory=$False)]
      [Object]$Object=$Null,
      [Parameter(Mandatory=$False)]
      [String]$EnumName="",
      [Parameter(Mandatory=$False)]
      [Object]$EnumObject=$Null,
      [Parameter(Mandatory=$False)]
      [System.Type]$EnumType=$Null)
    Try
    {
        If ($EnumType -NE $Null)
        {
            Write-Verbose "EnumType is $EnumType"
            $Names = [System.Enum]::GetNames($EnumType)
            $Output = "Switch("+"$"+"EnumObject){`n"
            ForEach($Name in $Names)
            {
                $Output += " ""$Name"" {`n"
                $Output += "             # Code for $Name`n" 
                $Output += "             Continue`n" 
                $Output += "             }`n" 
            }
            $Output += "}`n" 
            $Output 
        }
        ElseIf ($EnumObject -NE $Null)
        {
            Write-Verbose "EnumObject is $($EnumObject.GetType())"
            Get-EnumSwitchTemplate $EnumObject
        }
        ElseIf ($EnumName -NE "")
        {
            Write-Verbose "EnumName is $EnumName"
            Get-EnumSwitchTemplate $EnumName
        }
        ElseIf ($Object -Is [System.String])
        {
            Write-Verbose "Object is a string=$Object"
            Get-EnumSwitchTemplate (New-Object -TypeName $Object)
        }
        ElseIf ($Object -Is [System.Enum])
        {
            Write-Verbose "Object is an enum=$($Object.GetType())"
            Get-EnumSwitchTemplate -EnumType (($Object.GetType()) -As [System.Type])
        }
        ElseIf ($Object -Is [System.Type])
        {
            Write-Verbose "Object is a type=$Object"
            Get-EnumSwitchTemplate (New-Object -TypeName $Object)
        }
        ElseIf ($Object -NE $Null)
        {
            Write-Verbose "Object is not an enum"
        }
        Else
        {
            Write-Verbose "Object is Null"
        }
    }
    Catch [System.Exception]
    {
        Write-Host $_.Exception.Message
    }
}


Here is the output for the function being called for a string containing the enum name "System.Windows.Forms.FormWindowState" and for a string containing the name of the non-enum object "System.Windows.Forms.Form". The common parameter -Verbose is utilized to illustrate the calling of the function and how it arrives at the right object type, System.Type.

  

Here is the output for the function being called for an enum "System.Windows.Forms.FormWindowState" object and for a non-enum "System.Windows.Forms.Form" object . The common parameter -Verbose is utilized to illustrate the calling of the function and how it arrives at the right object type, System.Type.



Here is the output for the function being called for System.Type object for the enum class "System.Windows.Forms.FormWindowState" and for the System-Type object for the non-enum class "System.Windows.Forms.Form". The common parameter -Verbose is utilized to illustrate the calling of the function and how it arrives at the right object type, System.Type.



Here is the output for the function and the -EnumName parameter being called with a string containing the enum name "System.Windows.Forms.FormWindowState" and for a string containing the name of the non-enum object "System.Windows.Forms.Form". The common parameter -Verbose is utilized to illustrate the calling of the function and how it arrives at the right object type, System.Type.



Here is the output for the function and the -EnumObject parameter being called for an enum "System.Windows.Forms.FormWindowState" object and for a non-enum "System.Windows.Forms.Form" object . The common parameter -Verbose is utilized to illustrate the calling of the function and how it arrives at the right object type, System.Type.



Here is the output for the function and the -EnumType parameter being called for System.Type object for the enum class "System.Windows.Forms.FormWindowState" and for the System-Type object for the non-enum class "System.Windows.Forms.Form" which generates an exception message. The common parameter -Verbose is utilized to illustrate the calling of the function and how it arrives at the right object type, System.Type.




Epilogue: PowerShell ISE Add-on for Enums


A function that generates PowerShell source code for enums, makes for a good candidate for a PowerShell ISE Add-on. The PowerShell module EnumISEAddon.psm1 can be downloaded at the gallery PowerShell ISE Add-On to Generate a Switch Template for an Enum.