I have an function that fetches data, validates it against a set of user specified parameters and outputs if it is correct or not and based on that takes action, and it works just fine. As a further development of the function I've tried to move to a bitwise enumeration for the 'flags' but cannot get it to work like i want.
I want to switch through the enumeration and run the case for all possible 'matches' but i only get matches on the case when there is only a direct match on the value. Ie. when the value is 1 it runs the case 'Milk' but if the value is 3 it will not run the 'Milk' and the 'Bread' case ... i kinda assume its trying to run the 'Milk, Bread' case.
Is there any easy way that I've failed to see around this? ><
[Flags()] enum Breakfast {
Nothing = 0
Milk = 1
Bread = 2
Egg = 4
Bacon = 8
}
$BreakfastFlag = 3
Switch ([Breakfast]$BreakfastFlag){
Nothing {
Write-Host "No breakfast was selected" -ForegroundColor White -BackgroundColor Red
}
Milk {
Write-Host "Milk was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
Bread {
Write-Host "Bread was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
Egg {
Write-Host "Egg was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
Bacon {
Write-Host "Bacon was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
}
Yet another variant:
[Flags()] enum Breakfast {
Nothing = 0
Milk = 1
Bread = 2
Egg = 4
Bacon = 8
}
$BreakfastFlag = 3
Switch ([Breakfast]$BreakfastFlag)
{
Nothing {
Write-Host "No breakfast was selected" -ForegroundColor White -BackgroundColor Red
}
{ $_ -band [Breakfast]::Milk } {
Write-Host "Milk was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
{ $_ -band [Breakfast]::Bread } {
Write-Host "Bread was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
{ $_ -band [Breakfast]::Egg } {
Write-Host "Egg was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
{ $_ -band [Breakfast]::Bacon } {
Write-Host "Bacon was selected!" -ForegroundColor White -BackgroundColor DarkGreen
}
}
Output:
Milk was selected!
Bread was selected!
>> Script Ended
If brevity is the goal, make an auxiliary function that accepts a hashtable with keys as text names of the flags and values as anything, including a scriptblock:
function Switch-Flag($value, [hashtable]$switchboard) {
$type = $value.GetType()
$intValue = $value.value__
$parsed = New-Object $type
foreach ($e in $switchboard.GetEnumerator()) {
$key = $e.name
if ($key -is $type) {
$r = $key.value__
} elseif ($key -is [int]) {
$r = $key
} elseif ($type::TryParse($key, [ref]$parsed)) {
$r = $parsed.value__
} else {
continue
}
if (($intValue -band $r) -eq $r) {
if ($e.value -is [ScriptBlock]) {
$e.value.Invoke()
} else {
$e.value
}
}
}
}
Usage example 1, simplified:
[Breakfast]$flag = 3
Switch-Flag $flag @{
Milk = { Write-Host liquid }
Bread = { Write-Host crunchy }
}
Usage example 2, ensuring the order of choices:
$flag = 3
Switch-Flag ([Breakfast]$flag) ([ordered]@{
Milk = 'liquid'
Bread = 'crunchy'
})
Usage example 3, using enum as keys:
[Breakfast]$flag = 3
Switch-Flag $flag @{
([Breakfast]::Milk) = { $milk++ }
([Breakfast]::Bread) = { $bread++ }
}
P.S. This is 10 times slower than using -band
expressions shown in the other answer (180 microseconds vs 18 microseconds) because apparently PowerShell is smart enough to cache the expressions and it also runs the expression scriptblocks in local scope, that is, if I understand correctly, it doesn't create a new scope in case of switch expressions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With