I would like to add a 5 minutes progress bar in my Powershell script. I don't find the solution to run my progress bar and the other part of my script at the same time... Can someone help please ? Do I need to implement any thread ? Thank you.
Here is the progress bar :
$seconds = 60
$minutes = $seconds * 5
1..$minutes |ForEach-Object {
$percent = $_ * 100 / $minutes
Write-Progress -Activity "Créations des machines virtuelles" -Status "$([math]::ceiling((($minutes - $_) / 60))) minutes remaining..." -PercentComplete $percent
Start-Sleep -Seconds 1
}
CodePudding user response:
You can use a System.Timers.Timer
instance and subscribe to its Elapsed
events using Register-ObjectEvent
with a script block ({ ... }
) passed to its -Action
parameter, from where you can call Write-Progress
periodically.
This allows you to perform foreground operations as usual.
Here's a self-contained example:
# Initialize the progress display
$activity = 'Creating VMs...'
Write-Progress -Activity $activity -PercentComplete 0
$totalMinutes = 1 # How long to show the progress bar for.
$timerIntervalSecs = 3 # The interval for firing timer events
# Create an initially disabled timer that fires every $intervalSecs when enabled.
$timer = [System.Timers.Timer]::new($timerIntervalSecs * 1000)
# Register for the timer's "Elapsed" event.
# The relevant values are passed via a hashtable passed to the -MessageData parameter,
# which can be accesssed with $Event.MessageData inside the -Action script block.
# -Action script block - which runs in a dynamic module - full access to the caller's variables.
$eventJob = Register-ObjectEvent -InputObject $timer -EventName Elapsed -Action {
$endTime, $totalMinutes, $activity = $Event.MessageData.EndTime, $Event.MessageData.TotalMinutes, $Event.MessageData.Activity
$timeLeft = $endTime - (Get-Date)
$percent = (1 - $timeLeft.TotalSeconds / ($totalMinutes * 60)) * 100
if ($timeLeft -lt 0) { $percent = 100; $timeLeft = [timespan] 0 } # fully elapsed already.
Write-Progress -Activity $activity -Status "$([math]::Floor($percent))% complete, $([math]::Ceiling($timeLeft.TotalMinutes)) minute(s) remaining..." -PercentComplete $percent
} -MessageData (@{ EndTime = (Get-Date).AddMinutes($totalMinutes); TotalMinutes = $totalMinutes; Activity = $activity })
$timer.Start() # Start the timer.
Write-Verbose -vb 'Simulating foreground processing. Press Ctrl-C to exit.'
try {
# Simulate foreground processing.
while ($true) {
Write-Host -NoNewline .
# Sleep a little. Note: Event-processing is blocked during sleep.
Start-Sleep -Seconds 1
}
} finally {
# Cleanup.
$timer.Stop()
Remove-Job $eventJob -Force
Write-Progress -Activity $activity -Completed
}