Search code examples
powershellprogress-bar

Progress bar with a timer in PowerShell


I'm trying to create a progress bar in PowerShell, I would like the progress bar to reach 100% after certain amount of time. The below script does that but I have to click on the button to get it started. Is there way to start the progress bar right away without the need to click on the button? FYI: I'm simply trying to create a progress bar that will reach 100% after set amount of time. Below is my script:

Function StartProgressBar
{
    if($i -le 5){
        $pbrTest.Value = $i
        $script:i += 1
    }
    else {
        $timer.enabled = $false
    }   
}

$Form = New-Object System.Windows.Forms.Form
$Form.width = 400
$Form.height = 200
$Form.Text = "Add Resource"

# Init ProgressBar
$pbrTest = New-Object System.Windows.Forms.ProgressBar
$pbrTest.Maximum = 100
$pbrTest.Minimum = 0
$pbrTest.Location = new-object System.Drawing.Size(10,10)
$pbrTest.size = new-object System.Drawing.Size(100,50)
$i = 0
$Form.Controls.Add($pbrTest)

# Button
$btnConfirm = new-object System.Windows.Forms.Button
$btnConfirm.Location = new-object System.Drawing.Size(120,10)
$btnConfirm.Size = new-object System.Drawing.Size(100,30)
$btnConfirm.Text = "Start Progress"
$Form.Controls.Add($btnConfirm)

$timer = New-Object System.Windows.Forms.Timer 
$timer.Interval = 1000

$timer.add_Tick({
StartProgressBar
})

$timer.Enabled = $true
$timer.Start()

# Button Click Event to Run ProgressBar
$btnConfirm.Add_Click({
    
    While ($i -le 100) {
        $pbrTest.Value = $i
        Start-Sleep -m 1
        "VALUE EQ"
        $i
        $i += 1
    }
})

# Show Form
$Form.Add_Shown({$Form.Activate()})
$Form.ShowDialog() ```  

Solution

  • I made some adjustments to your code.

    • I have renamed your function StartProgressBar into Update-ProgressBar because it will be called upon on every timer tick to update the statusbar, so the name is more self explanatory I think
    • the button now is only there to re-start the progressbar if needed.
    • you don't need counter $i because the ProgressBar object itself has all properties you need to keep track of its current value. Also, if you do want a counter, inside the function (and other scriptblocks) you need to address it with $script:i. Without that script-scope, $i does not exist there.
    • to have the progressbar start running on startup, you need to enable and start the timer using $Form.Add_Shown({$timer.Enabled = $true; $timer.Start()})
    • to show the form on top of other windows, set $Form.Topmost = $true

    Here's the code:

    function Update-ProgressBar {
        # this function will be called on every timer tick
        $pbrTest.PerformStep()
        $progressLabel.Text = "VALUE EQ $($pbrTest.Value)%"
        
        if ($pbrTest.Value -ge $pbrTest.Maximum) {
            $timer.Enabled = $false
            $timer.Stop()
            $btnRestart.Enabled = $true
        }
    }
    
    $Form = New-Object System.Windows.Forms.Form
    $Form.Width = 400
    $Form.Height = 200
    $Form.Text = "Add Resource"
    $Form.Topmost = $true  # place this form on top
    
    # Init ProgressBar
    $pbrTest = New-Object System.Windows.Forms.ProgressBar
    $pbrTest.Location = New-Object System.Drawing.Point(10,10)
    $pbrTest.Size = New-Object System.Drawing.Size(100,50)
    $pbrTest.Maximum = 100
    $pbrTest.Minimum = 0
    $pbrTest.Value = 0
    $pbrTest.Step = 1
    $Form.Controls.Add($pbrTest)
    
    # Button
    $btnRestart = New-Object System.Windows.Forms.Button
    $btnRestart.Location = New-Object System.Drawing.Size(120,10)
    $btnRestart.Size = New-Object System.Drawing.Size(100,30)
    $btnRestart.Text = "Restart Progress"
    $btnRestart.Enabled = $false  # disabled at first
    $btnRestart.Add_Click({ 
        # disable this button while the progressbar is running
        $this.Enabled = $false  
        # reset the progressbar to value 0 and start the timer
        $pbrTest.Value = 0
        $timer.Enabled = $true
        $timer.Start()
    })
    $Form.Controls.Add($btnRestart)
    
    # Label
    $progressLabel = New-Object System.Windows.Forms.Label
    $progressLabel.Size = '370, 20'
    $progressLabel.Location = '10,70'
    $progressLabel.Text = "Processing..."
    $Form.Controls.Add($progressLabel)
    
    # Timer
    $timer = New-Object System.Windows.Forms.Timer 
    $timer.Interval = 50
    $timer.Enabled = $false  # disabled at first
    $timer.Add_Tick({ Update-ProgressBar })
    
    # start the timer as soon as the form is shown
    $Form.Add_Shown({$timer.Enabled = $true; $timer.Start()})
    
    # Show Form
    $Form.ShowDialog()
    
    # stop the timer and dispose of it and finally also dispose of the form
    $timer.Stop()
    $timer.Dispose()
    $pbrTest.Dispose()
    $Form.Dispose()