Adding Time Remaining to PowerShell Loop

I am going to start adding a few more blog posts covering PowerShell usage as I feel this will be quite useful for some people. These will be shorter to the point blogs covering a specific topic.

Today I will be looking at handling loop counters and displaying to the user the percentage and time remaining for a loop to complete.

This is something that is very useful to add to any long-running loop. If you don’t add some form of display you will have no real idea of the current state of a loop.

So let’s get scripting!

Code

#Example of loop to provide Percent Complete and Estimated Time Left

$folders = Get-ChildItem -Directory -depth 100

#Set counter to 0
$counter = 0
$startTime = Get-Date

foreach ($Folder in $Folders) {
    $Counter++
    #Workout elapsed time from the start time to now.
    $ElapsedTime = (Get-Date) - $StartTime
    $timeLeft = [TimeSpan]::FromMilliseconds((($ElapsedTime.TotalMilliseconds / $Counter) * ($Folders.Count - $Counter)))

    Write-Progress -Activity "Working on folder: $($Counter) of $($Folders.Count)" `
        -Status "Est Time Left: $($timeLeft.Days) Days, $($timeLeft.Hours) Hours, $($timeLeft.Minutes) Minutes, $($timeLeft.Seconds) Seconds" `
        -PercentComplete $([math]::ceiling($($Counter / $Folders.Count) * 100))
    
    # Logic to do task
    # Change permissions, get data etc.
    Start-Sleep -Seconds 1
}   

Explanation

First, we will grab a load of items to loop through to allow us to test the functionality.

Variables

In my case, I am just going to grab a list of folders with

$folders = Get-ChildItem -Directory -Depth 100

This gives me a fair amount of folders to work through for my loop.

Next, I set the $counter variable to 0, and get the current datetime into the $startTime variable.

Main Loop

In my case, I am doing a simple Foreach loop. Working through each folder in the $folders list.

In each iteration of the loop, I increase the $counter variable by 1

$counter++

I work out the Elapsed time by getting the current date time and then subtract the $startTime variable we created at the beginning of the script.

$ElapsedTime = (Get-Date) - $StartTime

Then we go into the main part. The calculation for the remaining time.

To calculate the estimated time left we create a TimeSpan object and then calculate the remaining time by taking the current elapsed time in milliseconds and dividing it by the current counter value.

This will give us the estimated time of a single loop.

We then multiply this value by the count of the remaining items. This is obtained by taking the total item count minus the current counter value.

The resulting $timeLeft variable contains a TimeSpan object for the estimated remaining time.

$timeLeft = [TimeSpan]::FromMilliseconds((($ElapsedTime.TotalMilliseconds / $Counter) * ($Folders.Count - $Counter)))

Write-Progress

The last step is to display this resultant remaining time on the screen.

We can use the built-in PowerShell Write-Progress command to do this.

    Write-Progress -Activity "Working on folder: $($Counter) of $($Folders.Count)" `
        -Status "Est Time Left: $($timeLeft.Days) Days, $($timeLeft.Hours) Hours, $($timeLeft.Minutes) Minutes, $($timeLeft.Seconds) Seconds" `
        -PercentComplete $([math]::ceiling($($Counter / $Folders.Count) * 100))

In the above command, we are using the -Status switch to write out the remaining time to the screen in Days, Hours, Minutes and Seconds

We also use the -PercentComplete switch to display a percentage. This is a simple calculation of the current counter value divided by the total item count multiplied by 100.

NB: I am having to round this percentage up to a single number however or the percentage shows as 100% until it reaches 0.5 percent. This is down with the [math]::ceiling command.

Testing

In the script, I have added a 1-second sleep with the Start-Sleep -Seconds 1 command. This is to allow the Write-Progress content to actually display (as my loop actually does nothing)

Running the script shows the progress is working nicely. And it seems my script will take approximately 1 hour and 15 minutes.

I can see the percentage is increasing and the time left is decreasing as the script runs. Success!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s