Etan Reisner
Etan Reisner

Reputation: 80941

Set-PSDebug -Trace 2 is causing my powershell code to throw an error that doesn't occur without tracing on

Imagine a script test.ps1 that looks like this:

Param (
    [ValidateNotNullOrEmpty()]
    $VMHost,

    [switch]
    $trace
)

$ErrorActionPreference = "Stop"
Set-StrictMode -Version 2

trap {
    Set-PSDebug -Trace 0
    $_.InvocationInfo
    break
}

if ($trace) {
    Set-PSDebug -Trace 2
}

if ($VMHost) {
    $VMHost = @(@($VMHost) | % {
        $h = $_
        Switch ($h.GetType().Name) {
            'String' {
                "isastring"
            }
            default {
                Write-Error -Category InvalidType -TargetObject $h -ErrorAction Stop -Message 'VMHost argument must be a String or a VMHost object.'
            }
        }
    })
}

When run normally it does this:

PS> & .\test.ps1 -VMHost "foo"
foo

When run with the -trace argument however it does this:

PS> & .\test.ps1 -VMHost "foo" -trace
DEBUG:   21+ if ( >>>> $VMHost) {
DEBUG:   22+      >>>> $VMHost = @(@($VMHost) | % {
DEBUG:   22+     $VMHost = @( >>>> @($VMHost) | % {
DEBUG:   22+     $VMHost = @(@( >>>> $VMHost) | % {
DEBUG:   22+     $VMHost = @(@($VMHost) | %  >>>> {
DEBUG:     ! CALL function '<ScriptBlock>'  (defined in file 'path...\test.ps1')
DEBUG:   23+          >>>> $h = $_
DEBUG:     ! SET $h = 'foo'.
DEBUG:     ! SET $switch = 'String'.
DEBUG:   24+         Switch ( >>>> $h.GetType().Name) {
DEBUG:     ! SET $switch = ''.
DEBUG:   35+      >>>> })
DEBUG:     ! SET $VMHost = ''.
DEBUG:   13+      >>>> Set-PSDebug -Trace 0
DEBUG:     ! CALL function '<ScriptBlock><trap>'  (defined in file
'path...\test.ps1')


MyCommand             :
BoundParameters       : {}
UnboundArguments      : {}
ScriptLineNumber      : 23
OffsetInLine          : 19
HistoryId             : -1
ScriptName            : path...\test.ps1
Line                  :     $VMHost = @(@($VMHost) | % {

PositionMessage       : At path...\test.ps1:23 char:19
                        +     $VMHost = @(@($VMHost) | % {
                        +                   ~~~~~~~
PSScriptRoot          : C:\Users\ereisner\TenableAppliancePackaging
PSCommandPath         : C:\Users\ereisner\TenableAppliancePackaging\test.ps1
InvocationName        :
PipelineLength        : 0
PipelinePosition      : 0
ExpectingInput        : False
CommandOrigin         : Internal
DisplayScriptPosition :

The variable cannot be validated because the value System.Object[] is not a valid value for the VMHost variable.
At path...\test.ps1:22 char:19
+     $VMHost = @(@($VMHost) | % {
+                   ~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : ValidateSetFailure

How is trace debugging causing an error like this?

What is powershell doing here?

Can this filter/assignment be cleanly rewritten to avoid this problem (bug?)?

Powershell version info:

PS> $PSVersionTable
Name                           Value
----                           -----
PSVersion                      3.0
WSManStackVersion              3.0
SerializationVersion           1.1.0.1
CLRVersion                     4.0.30319.42000
BuildVersion                   6.2.9200.16481
PSCompatibleVersions           {1.0, 2.0, 3.0}
PSRemotingProtocolVersion      2.2

Upvotes: 2

Views: 264

Answers (1)

Etan Reisner
Etan Reisner

Reputation: 80941

Not a full answer but it appears that this is a powershell version 3 bug.

The issue appears to be in how switch behaves in this scenario. It appears to "loop" one past the end of the single string argument it is given.

The same code run under PS 4 works as expected.

Upvotes: 1

Related Questions