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