Powershell "Set-PSDebug -Trace 2" Causes Unexpected Results

I had a strange problem when I had a different behavior when installing "Set-PSDebug -Trace 2".

I traced it to a switch statement that did not execute properly and was able to play it on PowerShell V3, but not on PowerShell V2 or Powershell V1 (works as expected)

Take the following simple function:

function DoTest { $result = "Switch Case Not Executed" $VendorName = "Microsoft" switch ($VendorName) { "Microsoft" { $result = "Switch Case Executed" } } Write-host "Switch: $($VendorName) -> $result" 

}

Now run the following:

 #Works as expected Set-PSDebug -Off; DoTest; #Doesn't work as expected Set-PSDebug -Trace 2; DoTest; 

PosH V3 Results with PSDebug Tracing

 DEBUG: 3+ Set-PSDebug -Trace 2; >>>> DoTest; DEBUG: 1+ function DoTest >>>> { DEBUG: ! CALL function 'DoTest' DEBUG: 2+ >>>> $result = "Switch Case Not Executed" DEBUG: ! SET $result = 'Switch Case Not Executed'. DEBUG: 3+ >>>> $VendorName = "Microsoft" DEBUG: ! SET $VendorName = 'Microsoft'. DEBUG: ! SET $switch = 'Microsoft'. DEBUG: 4+ switch ( >>>> $VendorName) DEBUG: ! SET $switch = ''. DEBUG: 9+ >>>> Write-host "Switch: $($VendorName) -> $result" DEBUG: 9+ Write-host "Switch: $( >>>> $VendorName) -> $result" Switch: Microsoft -> Switch Case Not Executed DEBUG: 11+ >>>> } 

In version 3 of PoSH, even a debug trace indicates that the value is set, but seems to completely ignore the switch statement. I even tried Set-StrictMode and everything works fine. This is only when PSDebug tracing is enabled. Is this behavior expected?

+7
switch-statement powershell
source share
1 answer

After an exhaustive investigation, it seems to be a bug in Powershell. The $switch variable gets clobbered in debug mode and ends up being some kind of array enumerator, on an empty array, or something stupid. I recommend submitting a question at http://connect.microsoft.com

Workaround 1:

 # Pro: No scoping differences between if statement blocks and function # Con: big piles of If ... else if ... else if ... can get really annoying to code and maintain # Con: Statements are limited to single execution, pipeline is lifted to function level instead of statement level ... same code as before but using an if instead of switch ... if($VendorName = 'Microsoft') { $result = "Switch Case Executed" } else { $result = "FAIL!" } 

Workaround 2:

 # Pro: Each script block is self-contained and has private scope # Pro: "cases" can be added without modifying DoIt function, and even passed into the function # Pro: "cases" can be used in a pipeline # Con: Indirect script blocks can be difficult to understand at first function DoTest { $result = "Switch Case Not Executed" $VendorName = "Microsoft" $SwitchHack = @{ Microsoft = { "Microsoft Case Executed" } Default = { "Default Case Executed" } } if($SwitchHack.Keys -contains $VendorName) { $result = $SwitchHack."$VendorName".InvokeReturnAsIs() } else { $result = $SwitchHack.Default.InvokeReturnAsIs() } 'Switch: {0} -> {1}' -f $VendorName, $result | Write-Host } Set-PSDebug -Trace 2 DoTest 

And since I was bored, I wrote "Workaround 3", which is only 2 when the switch went into function

 function Switch-Object { param( [Parameter(Mandatory=$true)] [String]$In, [Parameter(Mandatory=$true)] [hashtable]$Actions ) try { $Actions."$In".InvokeReturnAsIs() } catch { throw "Unknown Action Label" } } function DoTest { $result = "Switch Case Not Executed" $VendorName = "Microsoft" $VendorActions = @{ Microsoft = { "Microsoft Case Executed" } } $result = Switch-Object -On:$VendorName -Actions:$VendorActions 'Switch: {0} -> {1}' -f $VendorName, $result | Write-Host } Set-PSDebug -Trace 2 DoTest 
+2
source share

All Articles