From Basics to Binary: Supercharge your PowerShell enums

Listen to this blog post!

Table of contents:

Ready to level up your PowerShell enum game? Discover how [Flags()] transforms simple enums into powerful binary combinations, allowing you to manage multiple settings with elegant precision perfect for feature flags, permission systems, and configuration management.  

Tips by Tobias & Aleksandar:

Using enums

Simple enums define a list of allowed values, and the user can pick exactly one. When enums are defined as a flag array, then the user can pick more than one value:

[Flags()]

enum Features

{

   BootLog

   RealTimeProtection

   Firewall

   PhysicalAccess

   Leash

}



[Features]$myFeatures = 'Firewall', 'Leash'

$myFeatures

By adding the [Flags()] attribute to the enum, each enum entry now gets its own unique bit value, thus the user can combine as many enum items as needed. The type [Enum] can shed some light into this. Here it lists the defined enum names:

PS C:\> [Enum]::GetNames([Features])
PS C:\> [Enum]::GetNames([Features])

Next, it shows the assigned true numeric values:

PS C:\> [Enum]::GetNames([Features]) | ForEach-Object {
   '{0} = {1}' -f $_, ([Features]::$_ -as [int])
}
PS C:\> [Enum]::GetNames([Features]) | ForEach-Object { '{0} = {1}' -f $_, ([Features]::$_ -as [int]) }

When you assign multiple values, bit values are added:

PS C:\> [Features]$myFeatures = 'Firewall', 'Leash'
PS C:\> $myFeatures
Firewall, Leash 
PS C:\> $myFeatures.value__
PS C:\> [Features]$myFeatures = 'Firewall', 'Leash' PS C:\> $myFeatures Firewall, Leash PS C:\> $myFeatures.value__

There is just one problem: the assigned numbers are consecutive and thus ambiguous PhysicalAccess has ID 3, but RealTimeProtection+Firewall also adds to 3.

When you use [Flags()], you also need to manually assign unique values to the enum items:

[Flags()]

enum Features

{

   BootLog =  1

   RealTimeProtection = 2

   Firewall = 4

   PhysicalAccess = 8

   Leash = 16

}

Now each item has a unique ID:

PS C:\> [Enum]::GetNames([Features]) | ForEach-Object {'{0} = {1}' -f $_,
([Features]::$_ -as [int])}
PS C:\> [Enum]::GetNames([Features]) | ForEach-Object {'{0} = {1}' -f $_, ([Features]::$_ -as [int])}

Now, with unique IDs, you can use enums like any other numbers to do binary arithmetic:

PS C:\> [Features]'Bootlog,Leash'
BootLog, Leash
PS C:\> [Features]'Bootlog,Leash' -as [int]
PS C:\> [Features]'Bootlog,Leash' BootLog, Leash PS C:\> [Features]'Bootlog,Leash' -as [int]

Use the "+=" operator to add an element, and "-=" to remove it:

PS C:\> [Features]$features = 'Bootlog'
PS C:\> $features += 'Leash'
PS C:\> $features += 'Firewall'
PS C:\> $features
BootLog, Firewall, Leash
PS C:\> $features -= 'Leash'
PS C:\> $features
BootLog, Firewall
PS C:\> [Features]$features = 'Bootlog' PS C:\> $features += 'Leash' PS C:\> $features += 'Firewall' PS C:\> $features BootLog, Firewall, Leash PS C:\> $features -= 'Leash' PS C:\> $features BootLog, Firewall

Likewise, when testing whether a given value is present in such a list, use binary operators like -band and -bor:

PS C:\> $features
BootLog, Firewall
PS C:\> ($features -band 'Firewall') -eq 'Firewall'
True
PS C:\> ($features -band 'Leash') -eq 'Leash'
False
PS C:\> $features BootLog, Firewall PS C:\> ($features -band 'Firewall') -eq 'Firewall' True PS C:\> ($features -band 'Leash') -eq 'Leash' False

Related links