Using a Progress Bar Wisely

by Jan 19, 2017

PowerShell comes with support for progress bars. Here is a very simple example:

1..100 | ForEach-Object {
  Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $_
  Start-Sleep -Milliseconds 100
}

Using a progress bar can be valuable as long as you don’t call Write-Progress excessively. Especially with long-running loops, it makes no sense to call Write-Progress for each loop iteration. If you do, your scripts become very slow.

Let’s assume for example you have a loop that runs 10000 times. Displaying a progress bar will slow down the script considerably:

$min = 1
$max = 10000

$start = Get-Date

$min..$max | ForEach-Object {
  $percent = $_ * 100 / $max
  Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $percent
}

$end = Get-Date

($end-$start).TotalMilliseconds

This delay is directly related to the number of calls to Write-Progress, so if you change the value for $max to 100000, the script takes 10 times the time, just because Write-Progress is called 10 times more often.

That’s why you should add an intelligent mechanism to limit the number of calls to Write-Progress. The following example updates the progress bar in 0.1% increments:

$min = 1
$max = 10000

$start = Get-Date

# update progress bar every 0.1 %
$interval = $max / 1000

$min..$max | ForEach-Object {
  $percent = $_ * 100 / $max
  
  if ($_ % $interval -eq 0)
  {
    Write-Progress -Activity 'Counting' -Status "Processing $_" -PercentComplete $percent
  }
}

$end = Get-Date

($end-$start).TotalMilliseconds

When you increase the number for $max, you will now notice that the script won’t take much longer because the number of calls to Write-Progress stays the same.

Twitter This Tip! ReTweet this Tip!