Visualizing PowerShell pipeline

A picture1 is worth a thousand words.

Occasionally, I see people having issues while trying to understand how PowerShell pipeline is executed. Most of them have no problems when Begin/Process/End blocks are in the single function. And if in doubt, I can always point them to the Don Jones’ The Advanced Function Lifecycle article. But when multiple cmdlets are chained into the one single pipeline, things become a little less clear.

Consider this example.

function Use-Begin {
    Begin {
        Write-Host 'Begin'
    }
}

function Use-End {
    End {
        Write-Host 'End'
    }
}

Let’s try to pipe one function into another:

PS C:\Users\beatcracker> Use-Begin | Use-End

Begin
End

So far, so good, nothing unexpected. The Begin block of the Use-Begin function executes first, and the End block of the Use-End function executes last.

But what happens if we swap the functions in our pipeline?

PS C:\Users\beatcracker>  Use-End | Use-Begin

Begin
End

Gotcha! As you can see, nothing changed. Regardless of the position of the cmdlet in the pipeline, Begin blocks are always executed first and End blocks last. This could be a bit counterintuitive, because it’s easy to imagine pipeline like this:

Begin-1 {} -> Process-1 {} -> End-1 {} | Begin-2 {} -> Process-2 {} -> End-2 {}

When in fact, the pipeline goes this way:

Begin-1 {}
Begin-2 {}
    Process-1 {} | Process-2 {}
End-1 {}
End-2 {}

Which is more logical, when you think about it for a second: for every function in the pipeline, the Begin blocks have to be executed once, before the Process block and when Process blocks are finished iterating over every pipeline element, it’s time to finally run the End block. This gives us to the picture above.

To illustrate my point, I’ve created a View-Pipeline function, that generates a chained pipeline of advanced functions with Begin/Process/End blocks and displays their execution order. It makes it easy to visualize pipeline processing and get solid understanding of the pipeline lifecycle.

Here are some visualization examples made with this function:

  • One advanced function with Begin/Process/End blocks
PS C:\Users\beatcracker> View-Pipeline

View-Pipeline-1

[View-Pipeline-1]::Begin
    [View-Pipeline-1]::Process
      In : ""
      Out: "View-Pipeline-1"
[View-Pipeline-1]::End
  • Three advanced functions, each with its own Begin/Process/End blocks, passing one item through the pipeline
PS C:\Users\beatcracker> View-Pipeline -Pipes 3

View-Pipeline-1 | View-Pipeline-2 | View-Pipeline-3

[View-Pipeline-1]::Begin
[View-Pipeline-2]::Begin
[View-Pipeline-3]::Begin
    [View-Pipeline-1]::Process
      In : ""
      Out: "View-Pipeline-1"
        [View-Pipeline-2]::Process
          In : "View-Pipeline-1"
          Out: "View-Pipeline-2"
            [View-Pipeline-3]::Process
              In : "View-Pipeline-2"
              Out: "View-Pipeline-3"
[View-Pipeline-1]::End
[View-Pipeline-2]::End
[View-Pipeline-3]::End
  • Two advanced functions, with only Process/End blocks, passing two items through the pipeline
PS C:\Users\beatcracker> View-Pipeline -Pipes 2 -Items 2 -NoBegin

View-Pipeline-1 | View-Pipeline-2

    [View-Pipeline-1]::Process
      In : ""
      Out: "View-Pipeline-1"
        [View-Pipeline-2]::Process
          In : "View-Pipeline-1"
          Out: "View-Pipeline-2"
        [View-Pipeline-2]::Process
          In : "View-Pipeline-1"
          Out: "View-Pipeline-2"
[View-Pipeline-1]::End
[View-Pipeline-2]::End

That was easy, isn’t it?

I’m hoping that anyone, when shown this post, can get the gist of the PowerShell’s pipeline lifecycle in no time. If not – just let me know and I’ll do my best to improve it.


  1. There are actually no pictures here. Sorry.