Chris
Chris

Reputation: 77

Write-progress during Start-process -Wait

I'm trying to create an installation script and display a progress bar during the install.

$localfolder= (Get-Location).path
start-process -FilePath "$localfolder\Installer.exe" -ArgumentList "/silent /accepteula" -Wait

and as progress bar I want to add:

for($i = 0; $i -le 100; $i++)
{
Write-Progress -Activity "Installer" -PercentComplete $i -Status "Installing";
Sleep -Milliseconds 100;
}    

But I can't find the way to run the progress bar while the installer is running.

If someone has an idea...

Upvotes: 5

Views: 8119

Answers (2)

TheLostOne
TheLostOne

Reputation: 41

You can make the Progressbar into a function and call it whenever you need to.

Make sure you set this up: $ProgramName = "installer.exe" $Attributes = "/accepteula"

Function LoadingBar {For($I = 0; $I -le 100; $I = ($I + 1) % 100){Write-Progress -Activity "$ProgramName" -CurrentOperation "Please wait for instalation to complete... The bar will loop." -PercentComplete $I -Status "Installing";Start-Sleep -M 500;If ($LoadingProcess.HasExited) {Write-Progress -Activity "Installer" -Completed;Sleep 1;Break}}}

Then, you can call it like so,

$LoadingProcess = Start-Process -FilePath "F:\PortableApps\7zip\7zFM.exe" -ArgumentList "$Attributes" -PassThru;LoadingBar;Sleep 1;$LoadingProcess.WaitForExit() | Out-Null

This will display a progressbar at the top with the program name, action (Installing) and when the program is done, it will continue.

Upvotes: 1

briantist
briantist

Reputation: 47792

You could muck around with threading options, for your progress bar, but I don't recommend it.

Instead, forego -Wait with Start-Process, and use -PassThru to return a [System.Diagnostics.Process] object.

With that, you can check for the process having terminated yourself.

This is important for two reasons, both related to the fact that your progress bar isn't actually tracking the progress of the installation:

  1. You want to be able to abort the progress bar as soon as the process is finished.
  2. You maybe want to reset the progress bar to 0 if it happens to take longer than 10,000 milliseconds.

The Process object has a boolean property called .HasExited which you can use for this purpose.

With all that in mind, I'd do something like this:

$localfolder= (Get-Location).path
$process = Start-Process -FilePath "$localfolder\Installer.exe" -ArgumentList "/silent /accepteula" -PassThru

for($i = 0; $i -le 100; $i = ($i + 1) % 100)
{
    Write-Progress -Activity "Installer" -PercentComplete $i -Status "Installing"
    Start-Sleep -Milliseconds 100
    if ($process.HasExited) {
        Write-Progress -Activity "Installer" -Completed
        break
    }
}

Summary of Changes

  • Start-Process now uses -PassThru instead of -Wait and assigns the process object to the $process variable.
  • The for loop's iterator uses $i = ($i + 1) % 100 instead of $i++, so that it keeps resetting to 0 when it reaches 100.
  • An if block checks to see if the process has exited; if so, it ends the progress bar and then breaks out of the loop.

Slight caveat: the for loop is now an infinite loop that only breaks when the process exits. If the process is stuck, so is the loop. You could separately time the operation and handle a timeout if you wanted to.

Upvotes: 7

Related Questions