How to improve the performance of Write-Progress?

In such cases when progress is called too often I use this approach

# fast even with Write-Progress
$sw = [System.Diagnostics.Stopwatch]::StartNew()
for($e = 0; $e -lt 1mb; ++$e) {
    if ($sw.Elapsed.TotalMilliseconds -ge 500) {
        Write-Progress -Activity Test -Status "Done $e"
        $sw.Reset(); $sw.Start()
    }
}

# very slow due to Write-Progress
for($e = 0; $e -lt 1mb; ++$e) {
    Write-Progress -Activity Test -Status "Done $e"
}

Here is the suggestion on Connect....


I hope this helps someone else. I spent a day on a similar problem: Progress bar was very very slow.

My problem however was rooted in the fact that I had made the screenbuffer for the powershell console extremely wide (9999 instead of the default 120).

This caused Write-Progress to be slowed to the extreme every time it had to update the gui progress bar.


I completely removed my old answer for sake of efficiency, Although modulus checks are efficient enough, they do take time, especially if doing a modulus 20 against say 5 million - this adds a decent amount of overhead.

For loops, all I do is something simple as follows

---which is similar to the stop watch method, is reset your progress check with each write-progress:

$totalDone=0
$finalCount = $objects.count
$progressUpdate = [math]::floor($finalCount / 100)
$progressCheck = $progressUpdate+1
foreach ($object in $objects) {
    <<do something with $object>>
    $totalDone+=1
    If ($progressCheck -gt $progressUpdate){
        write-progress -activity "$totalDone out of $finalCount completed" -PercentComplete $(($totalDone / $finalCount) * 100)
        $progressCheck = 0
    }
    $progressCheck += 1
}

The reason I set $progressCheck to $progressUpdate+1 is because it will run the first time through the loop.

This method will run a progress update every 1% of completion. If you want more or less, just update the division from 100 to your prefered number. 200 would mean an update every 0.5% and 50 would mean every 2%


I wanted to use write-progress to monitor the piping of get-child-item to file. The solution was to start a new job and then monitor the output of the job for change from another process. Powershell makes this quite easy.

 # start the job to write the file index to the cache
 $job = start-job {
     param($path)
     Get-ChildItem -Name -Attributes !D -Recurse $path > $path/.hscache
 } -arg $(pwd) 

 # Wake every 200 ms and print the progress to the screen until the job is finished
 while( $job.State -ne "Completed") {
        Write-Progress -Activity ".hscache-build " -Status $(get-childitem .hscache).length
        sleep -m 200
 }

# clear the progress bar
Write-Progress -Activity ".hscache-build" -Completed

enter image description here