Author Posts

September 24, 2015 at 6:47 am

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

September 24, 2015 at 6:55 am

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 :).

September 24, 2015 at 7:04 am

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.

September 24, 2015 at 10:22 am

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

September 25, 2015 at 12:18 am

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.

September 25, 2015 at 7:00 am

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?

September 25, 2015 at 11:22 am

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.