Progress Bar and Seconds Remaining

In my last post about using progress bars in PowerShell, we went through the basic usage, as well as nesting of progress bars. There was however one parameter that I didn’t discuss, and that I seldom see used; the SecondsRemaining parameter.

As the name implies, this parameter lets you give feedback on the seconds remaining of the total task when using the Write-Progress cmdlet. In this blog post I’m going to show you how to calculate seconds remaining and show you a code snippet that you can use to easily add a progress bar to your script (or function).

While calculating the percent free value for the task you are working on are quite trivial, calculating how many seconds remain until it is finished is a little bit harder. And not only is it harder, but it can be highly unstable, and give you some strange results. The reason for this of course, is that unless you happen to know exactly how many seconds each step in your task (or each iteration of your collection) takes, you have to estimate the remaining seconds.

I have created a code snippet that can come in handy when working with progress bars in PowerShell. Let’s look at the code:


$array = 'item01', 'item02', 'item03', 'item04'
$count = 0
$start = Get-Date
[nullable[double]]$secondsRemaining = $null
foreach ($item in $array) {
$count++
# calculate percent complete
$percentComplete = ($count / $array.Count) * 100
# Define parameters for Write-Progress
$progressParameters = @{
Activity = "Doing my ting [$($count)/$($array.Count)] $($secondsElapsed.ToString('hh\:mm\:ss'))"
Status = 'Processing'
CurrentOperation = "Doing something with $item"
PercentComplete = $percentComplete
}
# if we have an estimate for the time remaining, add it to the Write-Progress parameters
if ($secondsRemaining) {
$progressParameters.SecondsRemaining = $secondsRemaining
}
# Write the progress bar
Write-Progress @progressParameters
# Insert code to be performed in each iteration of the array here
Start-Sleep -Milliseconds (Get-Random -Minimum 700 -Maximum 2000)
# estimate the time remaining
$secondsElapsed = (Get-Date) – $start
$secondsRemaining = ($secondsElapsed.TotalSeconds / $count) * ($array.Count – $count)
}
# Optional, if the progress bar don't go away by itself, un-comment this line
#Write-Progress -Activity 'Doing my thing' -Completed

Ok, let’s go through the code to understand what’s going on here.

[Lines 1-4] First we define our array of course. Then we set up a counter to keep track of our progress through the array, as well as take a note of the time before we enter the first item in the loop. I also set up a variable to hold the estimated seconds remaining. Note that I have defined it as a nullable type (of double). The reason for this is that for the first call to Write-Progress we won’t have any estimated time, since we haven’t calculated it yet.

[Line 10] Here we are calculating the percent free value.

[Lines 13-23] I’m setting up the parameters to Write-Progress as a hash table, so that it’s a bit easier to read. I’m also only adding the estimated time remaining if I actually have a value for it.

[Line 26] Here I’m calling Write-Progress to update the progress bar.

[Line 29] This is the “actual” code that we want to perform in the loop. If you are using this code snippet, replace with whatever code you want.

[Lines 32-33] This is the calculation of the estimated time remaining. First we are averaging out the total time elapsed so far with the number of times we have been through the loop. Then we multiply this number with the remaining items in the array. This gives us an best-effort estimate of the seconds remaining before we are done with all the iterations through the loop.

[Line 37] Sometimes you might encounter times when the progress bar is “stuck”. If that happens, un-comment this line to tell PowerShell that the progress bar have completed.

As an added bonus, as you might have noticed, I have also included the total running time of the looped code in the activity parameter of Write-Progress. Since we are getting this as part of the estimated time remaining calculation, we might as well use it, right?

I hope this little snippet can come in handy the next time you want to use a progress bar. Until next time!

One comment

Leave a comment