PowerShell Classes Part 2 — Enumerated Types

PowerShell Classes

In my previous article, Creating Your First PowerShell Class, I introduced you to the concept of a programming class. Using an example of a “Rock” class, I discussed how to create a class in PowerShell using the class{} keyword, how to add properties to a class, and how to instantiate or create an instance of a class. In this article, I am going to expand on the “Rock” class by defining allowed values for a few properties using an enumerated type or simply called an enum.



Revisiting the Rock Class

To recap, the Rock class definition contained 7 properties: Color, Luster, Shape, Texture, Pattern, Size, and Location. The first 6 properties were String properties and Location was an integer or a distance between some arbitrary point and the rock itself.

In addition, I also used the New() constructor to create an instance of the rock and once I had an instance of the rock defined ($Rock), I could assign properties to it.

Limiting Allowed Values using an Enum

Using string types for the rock properties will allow for an endless combination of possible property values. For example, I could define an instance of a rock’s size to be “HUGE” (as in the example above) or I could define it to be “VeryVeryLarge”. Conversely, I could define it as “teeny-tiny” or crumb-sized”. In this case, I want to limit the possible values for size to be only sizes that I have defined, like the shirt sizes of small, medium, and large. In order to accomplish this, I can use an enumerated type (also known as an enum) or a set of named values to define those possible values. Notice that the phrase is “enumerated type”. I am defining a custom type named “Size”.

Code Placement for Enums

When writing the code, place the enum definition outside the class definition or in its own file. I placed this Size enum in a file named C:\PowerShell\SizeEnum.ps1. That way, I can dot-source the enum. Why would I want to do this? If I place the enum in its own file, I can dot-source it for any class or function. That is right, enums are not just for PowerShell classes. I can use it to define custom types for functions as well, as shown in the function below.

PowerShell Death Match: Enums vs. ValidateSet

ValidateSet is an incredibly useful parameter validation attribute used in advanced functions to limit the possible input values for a given parameter. In comparison to an enum, ValidateSet does not define a custom type. It only limits the possible values of a parameter. As a result, the benefit of using ValidateSet is being able to use the methods of the defined parameter type. For example, a string type with a ValidateSet allows me to manipulate the string values using string methods. However, the downside of ValidateSet is that the set must be redefined each time you want to use it.

One Reason to Use ValidateSet

Consider the following function: it contains a parameter named Size and uses ValidateSet. However, notice that the parameter type is still [string]. In this simple example, I am taking the Size parameter and returning the 1st character as output.
ClassesPt2 1

This same function would not work using the Size enum:

ClassesPt2 2

Enums Make Sense for Custom Types

ValidateSet makes sense in the situation seen above when the methods of the underlying type need to be accessed. If you are going to do string manipulation on the values, it makes sense to keep the parameters as strings. I prefer ValidateSet for functions. This, along with all the other Validate* parameter attributes, is listed in the PowerShell help under about_Functions_advanced_parameters. The about_Classes help file, however, specifically states that the PowerShell language is adding support for classes and other user-defined types. This is the key here and the reason why I would choose an enum over a ValidateSet. This is the best route if I want the property or parameter to be of a custom type and limited to specific values.

Enums and Reuse

In conclusion, reuse enumerated types whenever possible to simplify the code and parameter declarations. Since the enum is valid for the life of the session, classes or functions that go together and make use of the same or similar parameters can all use the same enum definition. This is the case whether it be at the beginning of the class module, in a module that contains functions, or in its own file and dot-sourced into the module containing the code. Lastly, simplify the code using an enum rather than having to declare multiple validateSets.