Debugging Advanced functions with multi line string assignment problems

This topic contains 7 replies, has 4 voices, and was last updated by  Stephen Yeadon 1 year, 12 months ago.

  • Author
    Posts
  • #30026

    Stephen Yeadon
    Participant

    Hi,

    I have been spending some time trying to get my head around the pipe line specifically when passing collections across it and which sections of code get executed when [Begin, Process, End]. Please feel free to explain that to me. But my actual problem is something that I have come across when researching the above.

    If I define a multi line string in either the begin or process block I can no longer debug my code. And by that I mean that I can not step through the assignment of this string. If I F5 past the assignment to a later break point all is well but trying to step through the string assignment always throws the following exception which completely kills my session:

    Specified argument was out of the range of valid values.
    Parameter name: length
    At C:\Temp\Test.ps1:11 char:9
    + $x="
    + ~~~~
    + CategoryInfo : OperationStopped: (:) [], ArgumentOutOfRangeException
    + FullyQualifiedErrorId : System.ArgumentOutOfRangeException

    function Test {
        [CmdletBinding(DefaultParameterSetName='Parameter Set 1', 
                      SupportsShouldProcess=$true, 
                      PositionalBinding=$false,
                      HelpUri = 'http://www.microsoft.com/',
                      ConfirmImpact='Medium')]
        Param ( )
    
        Begin {
            $y=''
            $x="
    boo
    "
        }
        Process {
            if ($pscmdlet.ShouldProcess("Target", "Operation")) {
                $x
            }
        }
        End {
        }
    }
    
    Test
    
  • #30028

    Don Jones
    Keymaster

    My "Toolmaking" book does a pretty good job of explaining the lifecycle. But, in general:

    * When a function is run without pipeline input, BEGIN/PROCESS/END are basically ignored and the code within them runs top to bottom as if they didn't exist.
    * When a function is run with pipeline input, BEGIN runs first, then PROCESS runs and is handed one input object at a time, and then END runs when they're all done.

    For multi-line strings, you should be using a here-string:

    $x = @"This
    is
    all
    one "thing"
    "@
    

    That's a really useless HelpUri, BTW :).

  • #30029

    Stephen Yeadon
    Participant

    Agreed its a Ctrl +J default. Don I previously attempted to use the here-string and got the same results. The ISE does not seem to like stepping through multi line string assignment.

  • #30048

    Curtis Smith
    Participant

    Stephen, here is some sample code to show how powershell processes the begin, process and end blocks with pipeline and non-pipeline input. What you will see is that, as Don mentions, it run begin first, then process for each object and then end. What might not be clear is that PowerShell runs the Begin block for every cmdlet/function in the pipeline before running the begin for any other cmdlet/function as shown in the example below. So if you are expecting to use an input object in the begin block of your function, it will not work.

    Function Function1 {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName=$True)]
        [string]$message
    )
    Begin {Write-Verbose "Begin Function1: $message"}
    Process {
        Write-Verbose "Process Function1: $message"
        [PSCustomObject]@{
            message = $message
        }
    }
    End {Write-Verbose "End Function1: $message"}
    }
    
    Function Function2 {
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName=$True)]
        [string]$message
    )
    Begin {Write-Verbose "Begin Function2: $message"}
    Process {
        Write-Verbose "Process Function2: $message"
        [PSCustomObject]@{
            message = $message
        }
    }
    End {Write-Verbose "End Function2: $message"}
    }
    

    Test Function1


    PS C:\> function1 -message "Test" -verbose
    VERBOSE: Begin Function1: Test
    VERBOSE: Process Function1: Test

    message
    -------
    Test
    VERBOSE: End Function1: Test

    Test Function2


    PS C:\> function2 -message "Test" -verbose
    VERBOSE: Begin Function2: Test
    VERBOSE: Process Function2: Test

    message
    -------
    Test
    VERBOSE: End Function2: Test

    Test Function1 Pipe to Function2


    PS C:\> function1 -message "Test" -verbose | function2 -Verbose
    VERBOSE: Begin Function1: Test
    VERBOSE: Begin Function2:
    VERBOSE: Process Function1: Test
    VERBOSE: Process Function2: Test

    message
    -------
    Test
    VERBOSE: End Function1: Test
    VERBOSE: End Function2: Test

  • #30104

    Stephen Yeadon
    Participant

    Thanks everyone. The pipeline while mysterious now makes a lot more sense. Or at least I now know the order in which the distinct script blocks execute.

    What I'm still not sure about is whether the ISE has a bug regarding the debugging of code where there is a multi line string declaration or whether I have a really strange edge case. Has anyone come across this issue in their code? If you have time the code sample I provided will reproduce teh problem.

  • #30129

    David Johnson
    Participant

    On my Win7 machine running PSv3, I don't get the error you do when running that script.
    Converting to a here string also works.

    It's referencing a parameter name of "length", is that something from another script?

  • #30143

    Curtis Smith
    Participant

    Stephen, I get your same error using the ISE and a multiple string, including with a here-string. I suspect it is an issue with ISE during debugging.

  • #30174

    Stephen Yeadon
    Participant

    Thanks very much for looking into this for me. I have raised a user voice ticket to address this issue.
    https://windows.uservoice.com/forums/265757-windows-feature-suggestions/suggestions/9950631-powershell-ise-debugging-bug-when-declaring-multi

You must be logged in to reply to this topic.