Home > database >  Add a 5 minutes progress bar in powershell
Add a 5 minutes progress bar in powershell

Time:01-18

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
}
  • Related