Pffffieeuw… This was quite the puzzle! Finally got an easy progress bar when I need to execute those long-running batch commands.

Just use this function in your pipeline. It works the same as a Foreach-Object loop. Only it displays a progress bar 🙂


1..200 | Show-Progress { $_ }
Executing your command

How does it work?

Show-Progress is just a fancy way of using Write-Progress. It accepts 2 parameters: $Input and $ScriptBlock.


This parameter accepts your current object in the pipeline. It then adds a new property ItemNumber. $ItemNumber is used to calculate how much items are piped through. $PipelineBuffer then stores the entire object so that we can use this “new” object in our next pipe.


Next, the scriptblock takes over. The $ScriptBlock parameter tries to be what it says it would be. That is, a scriptblock.

Since we essentially copied over the piped object to our $PipelineBuffer, we can easily use this object as if it were the original. Only addition is the $Itemnumber. So, we simply use this object to perform our scriptblock on.


Now, we can calculate our $PercentageComplete. Since we used $a as a temporary counter and since we didn’t update it since our last object, this reflects the total amount of items in our original object.

$a = Total amount of items in original object
$ItemNumber = Number of the current item in the pipeline

$PercentageComplete = 100 / $a * ($_.ItemNumber + 1)

And here is the code:

function Show-Progress {
    param (
    $PipelineBuffer = $Input | ForEach-Object -Begin {$a = 0} {
        Add-Member -NotePropertyName ItemNumber -NotePropertyValue $a -InputObject $_ -PassThru
        $a ++
    $PipelineBuffer | ForEach-Object {
        $PercentageComplete = 100 / $a * ($_.ItemNumber + 1)
        Write-Progress -PercentComplete $PercentageComplete -Activity "Executing command" -Status "$PercentageComplete% complete"
        Invoke-Command $ScriptBlock