Introduction
In my last two posts, I introduced the concept of Enums in PowerShell, then got into some of the more advanced uses. In this post we’ll examine a special way to use an enum, known as a Flag.
First let me mention that for all of the examples we’ll display the code, then under it the result of our code. In this article I’ll be using PowerShell Core, 7.2, and VSCode. The examples should work in PowerShell 5.1 in the PowerShell IDE, although they’ve not been tested there.
To run a snippet of code highlight the lines you want to execute, then in VSCode press F8 or in the IDE F5. You can display the contents of any variable by highlighting it and using F8/F5.
A Brief Refresher on Binary Math
In order to understand how flags work you need at least a basic understanding of binary math. In this section I’ll see if I can’t provide a short, simple refresher on the subject.
In my previous article, I mentioned that I am a ham radio operator, and am a member of multiple clubs. In a small club it’s not unusual to hold multiple offices, for example I’m both the secretary and the webmaster for one of the clubs, as well as a paid member. We can denote this by using a single variable to hold this information through the use of an enum flag.
A flag is a single variable that can be broken into its individual bits to indicate multiple values. In our example, we’ll use a flag to indicate a member’s paid status, their office, and if they hold more than one position in the club, all with a single variable.
Let’s say we have six people standing in a row. Each person has a sign, the first reads "paid", the rest have the names of club offices.
When a member walks into a room, people hold up signs that indicate the person’s status in the club, while the others leave their signs face down. When the Vice President walks in, the paid sign is raised up, as is the Vice President sign. We then take a photograph to capture this information in a single place.
I happen to be both Secretary and Webmaster of my club, as well as a paid member, so in my case three signs would go up and be captured in a photo. If we happen to have a visitor to the club, none of the signs will be raised, and a photo will record that.
Bit flags work the same way. Each sign is a bit, and the photo corresponds to the variable that holds all the bits.
Let’s say we have a 32 bit integer. If all 32 of the bits are set to a 0, then the value of that integer will be 0.
If the bit in position one is set to 1, and all of the other bits are 0, it indicates the value of the variable is 1.
In the second bit position, if the value is set to 1 and all other bits set to 0, the integer value is 2. If both bits one and two are set to 1, the integer value will be 3, and so on.
This chart of binary numbers and their decimal counterparts may help clarify.
Binary | Decimal |
---|---|
0000 | 0 |
0001 | 1 |
0010 | 2 |
0011 | 3 |
0100 | 4 |
0101 | 5 |
0110 | 6 |
0111 | 7 |
1000 | 8 |
1001 | 9 |
1010 | 10 |
These are just the first few as an example, you could continue this chart into the trillions of values if not higher.
Should you need a further refresher on binary numbers, I’d suggest the Binary Number article on Wikipedia as a good guide. It’s important to understand binary values in order to fully understand how flags work.
Enum Flags
Let’s create our own enum flag to hold the status of club members. You declare an enum as a flag by placing the [Flags()]
modifier in front of the enum declaration, as you’ll see below. Note that the values must correspond to the integer value if a bit is set. The Wikipedia article includes a nice chart that shows a decimal number and what that number looks like in binary.
[Flags()] enum MemberStatus
{
Paid = 1
President = 2
VicePresident = 4
Secretary = 8
Treasurer = 16
Webmaster = 32
}
I could add more to this list if needed, using the value of 64 for the next member status, then 128, then 256, and so on.
Now lets represent a member status in a variable to show a member is the Vice President, and is also a paid member. To do so, we simply add the various statuses together.
$memStatus = [MemberStatus]::Paid + [MemberStatus]::VicePresident
$memStatus
Result:
Paid, VicePresident
What’s nice about using an enum flag is that when we display the variable PowerShell converts the flags back into the members from the enum.
We could also simply assign the total number. In this case, Paid (value of 1), plus Vice President (value 4), adds up to 5.
$memStatus = [MemberStatus] 5
$memStatus
Result:
Paid, VicePresident
Finally, if we want to display the numeric value behind our flag, we can cast it as an int
.
[int]$memStatus
Result:
5
Is the Flag Set? HasFlag to the Rescue!
Often you will want to see if a specific flag is set, for example we want to see if a member is paid. Now, if the paid status is the only flag set, it’s easy, just use $someVariable -eq [MemberStatus]::Paid
.
It gets much more complex if a variable has multiple flags set. Fortunately, enums have a method built in called HasFlag
you can use to test with.
First, let’s load a variable with several flags from our MemberStatus
enum.
$memStatus = [MemberStatus]::Webmaster + [MemberStatus]::Secretary + [MemberStatus]::Paid
$memStatus
Result:
Paid, Secretary, Webmaster
So now we’ve got our $memStatus
variable loaded with multiple statuses. Also note that even though we added the status in reverse order, they are always returned in ascending order from the enum declaration.
Now we want to know if our secretary / webmaster has paid their dues for the year. To do so, we’ll call the HasFlag
method of our variable, and pass in the status we wish to check.
$memStatus.HasFlag([MemberStatus]::Paid)
Result:
True
The GetHashCode Method
So far, when we’ve wanted to see the value of our enum derived variable, we’ve used [int]
to cast the variable in integer form.
$memStatus = [MemberStatus]::Webmaster + [MemberStatus]::Secretary + [MemberStatus]::Paid
[int]$memStatus
Result:
41
This shortcut works, and is something I’ve seen in many blog posts and examples. However, there is a method that is more clear in terms of code self-documentation. Like using [int]
, it will return an unsigned, 32 bit integer: GetHashCode
.
$memStatus = [MemberStatus]::Webmaster + [MemberStatus]::Secretary + [MemberStatus]::Paid
$memStatus.GetHashCode()
Result:
41
Both methods work, but in my opinion GetHashCode
is clearer in terms of intention, especially to someone unfamiliar with enum flags. Whichever route you go I suggest being consistent throughout your code.
Conclusion
This article focused on the use of enums as flags. While it is not something I use frequently, enum flags can be extremely useful when an item can have multiple states simultaneously. Our club member status is one such example, another is file attributes. A file could have both the hidden and compressed attributes.
Enum flags can reduce the size of your data for an item. Rather than having six individual variables for the six member statuses, a single variable can hold them all. This reduction in the size of your data can be even more valuable when that data is being stored in a database or file.
The demos in this series of blog posts were derived from my Pluralsight course PowerShell 7 Quick Start for Developers on Linux, macOS and Windows, one of many PowerShell courses I have on Pluralsight. All of my courses are linked on my About Me page.
If you don’t have a Pluralsight subscription, just go to my list of courses on Pluralsight . At the top is a Try For Free button you can use to get a free 10 day subscription to Pluralsight, with which you can watch my courses, or any other course on the site.