带运行空间的 powershell winforms gui - 如何让进度条工作以跨运行空间下载文件

问题描述 投票:0回答:0

我试图让进度条在表单上工作,但我他妈的无法让它工作。这里的主要焦点是下载文件,并在显示下载进度的表单上有一个进度条。表单和代码在不同的运行空间中运行,因此进度条控件似乎没有从“代码运行空间”更新。我绝不是编码员或 PowerShell 专家。这是我主要从这个网站整理出来的,然后用谷歌搜索所有的废话。

如果有人可以帮助甚至指出我正确的方向,那将有所帮助。

下面是我的脚本。

#Hash table for runspaces
$hash = [hashtable]::Synchronized(@{})

#FUNCIONS
#Append output to text box display.
Function Add-OutputBoxLine {
    Param ($Message)
    $hash.results.AppendText("$Message")
    $hash.results.Refresh()
    $script:hash.results.ScrollToCaret()
    $script:hash.results.SelectionStart = $hash.results.Text.Length
    $hash.results.Selectioncolor = "WindowText"
    $hash.Form.Refresh()
}

Function closeForm() 
{ $hash.form.close() }

Function RunAppCode {

    $scriptRun = {
        #Suppress Errors as to not interrupt the GUI experience. Comment these out when debugging.
        $script:ErrorActionPreference = 'SilentlyContinue'
        #$script:ProgressPreference = 'SilentlyContinue'

        $hash.results.Clear()
        $hash.start_button.Enabled = $false
        $hash.start_button.IsAccessible = $false

        #VARIABLES WITHIN scriptRun

        #Download link for stuff
        $Url = 'https://releases.ubuntu.com/22.04.2/ubuntu-22.04.2-desktop-amd64.iso'

        #Variable for downloads directory
        $downloadhome = (New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path

        #Variable for where stuff zip file will be downloaded to
        $downloadzipfile = $downloadhome + "\stuff.iso"
    
        #Download latest stuff
        $hash.results.AppendText("`r`n<:.info.:> Downloading latest stuff")
        Get-ChildItem -Path $downloadhome -Filter stuff.iso | Remove-Item -Force
        $global:ProgressPreference = "Continue"
        Start-Sleep -Seconds 3
        $hash.label1.text = "Downloading..."
        #$hash.form.controls.AddRange(@($hash.progressbar1,$hash.label1))
        #$hash.label1.Visible
        #$hash.progressbar1.Visible
        #Start-Sleep 20
        #exit
        
        #Funtion is here because I can't get it to work when not in this runspace 
        function DownloadFile($url1, $targetFile) {
            $uri = New-Object "System.Uri" "$url1"
            $request = [System.Net.HttpWebRequest]::Create($uri)
            $request.set_Timeout(15000) #15 second timeout
            $response = $request.GetResponse()
            $totalLength = [System.Math]::Floor($response.get_ContentLength() / 1024)
            $responseStream = $response.GetResponseStream()
            $targetStream = New-Object -TypeName System.IO.FileStream -ArgumentList $targetFile, Create
            $buffer = new-object byte[] 10KB
            $count = $responseStream.Read($buffer, 0, $buffer.length)
            $downloadedBytes = $count

            while ($count -gt 0) {
                $targetStream.Write($buffer, 0, $count)
                $count = $responseStream.Read($buffer, 0, $buffer.length)
                $downloadedBytes = $downloadedBytes + $count
                Write-Progress -activity "Downloading file '$($url1.split('/') | Select -Last 1)'" -status "Downloaded ($([System.Math]::Floor($downloadedBytes/1024))K of $($totalLength)K): " -PercentComplete ((([System.Math]::Floor($downloadedBytes / 1024)) / $totalLength) * 100)
            }
            Write-Progress -activity "Finished downloading file '$($url1.split('/') | Select -Last 1)'"
            $targetStream.Flush()
            $targetStream.Close()
            $targetStream.Dispose()
            $responseStream.Dispose()

        }
        
        $download =
        try {
            #Invoke-WebRequest -Uri $Url -OutFile $downloadzipfile -ErrorAction Stop
            DownloadFile $url $downloadzipfile
        }
        catch {
            $err = $_
            $results.text += "`r`n" + "<:.erro.:> $err"
        }

        $job = Start-Job -ScriptBlock { $download }
        do { [System.Windows.Forms.Application]::DoEvents() } until ($job.State -eq "Completed")
        Remove-Job -Job $job -Force

        $hash.label1.Text = "Download Complete"
        $hash.label1.Hide()
        $hash.progressbar1.Hide()
        Start-Sleep -Seconds 3

    } #Close the $scriptRun brackets for the runspace

    
    #Configure max thread count for RunspacePool.
    $maxthreads = [int]$env:NUMBER_OF_PROCESSORS
    
    #Create a new session state for parsing variables ie hashtable into our runspace.
    $hashVars = New-object System.Management.Automation.Runspaces.SessionStateVariableEntry -ArgumentList 'hash', $hash, $Null
    $InitialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault()
    
    #Add the variable to the RunspacePool sessionstate
    $InitialSessionState.Variables.Add($hashVars)

    #Create our runspace pool. We are entering three parameters here min thread count, max thread count and host machine of where these runspaces should be made.
    $script:runspace = [runspacefactory]::CreateRunspacePool(1, $maxthreads, $InitialSessionState, $Host)
        
    #Create a PowerShell instance.
    $script:powershell = [powershell]::Create()
    
    #Open a RunspacePool instance.
    $script:runspace.Open()
            
        
    #Add our main code to be run via $scriptRun within our RunspacePool.
    $script:powershell.AddScript($scriptRun)
    $script:powershell.RunspacePool = $script:runspace
        
    #Run our RunspacePool.
    $script:handle = $script:powershell.BeginInvoke()

    #Cleanup our RunspacePool threads when they are complete ie. GC.
    if ($script:handle.IsCompleted) {
        $script:powershell.EndInvoke($script:handle)
        $script:powershell.Dispose()
        $script:runspace.Dispose()
        $script:runspace.Close()
        [System.GC]::Collect()
    }
} 
 
#Closing the function.
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()

# Main Form
$hash.form = New-Object system.Windows.Forms.Form
$hash.form.ClientSize = New-Object System.Drawing.Point(811, 483)
$hash.form.text = "Stuff"
$hash.form.TopMost = $false
$hash.form.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")
$hash.form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::Fixed3D
$hash.form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen

$hash.okla_logo = New-Object system.Windows.Forms.PictureBox
$hash.okla_logo.width = 454
$hash.okla_logo.height = 159
$hash.okla_logo.location = New-Object System.Drawing.Point(43, -2)
$hash.okla_logo.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom
$hash.okla_logo.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")

$hash.aao_logo = New-Object system.Windows.Forms.PictureBox
$hash.aao_logo.width = 129
$hash.aao_logo.height = 99
$hash.aao_logo.location = New-Object System.Drawing.Point(652, 370)
$hash.aao_logo.SizeMode = [System.Windows.Forms.PictureBoxSizeMode]::zoom

$hash.exit_button = New-Object system.Windows.Forms.Button
$hash.exit_button.text = "Exit"
$hash.exit_button.width = 112
$hash.exit_button.height = 35
$hash.exit_button.location = New-Object System.Drawing.Point(536, 214)
$hash.exit_button.Font = New-Object System.Drawing.Font('Calibri', 10, [System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))
$hash.exit_button.ForeColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")
$hash.exit_button.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#ffffff")

$hash.start_button = New-Object system.Windows.Forms.Button
$hash.start_button.text = "Download"
$hash.start_button.width = 112
$hash.start_button.height = 35
$hash.start_button.location = New-Object System.Drawing.Point(536, 162)
$hash.start_button.Font = New-Object System.Drawing.Font('Calibri', 10, [System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))
$hash.start_button.ForeColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")
$hash.start_button.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#ffffff")

$hash.results = New-Object System.Windows.Forms.TextBox
$hash.results.multiline = $true
$hash.results.Scrollbars = "Vertical"
$hash.results.width = 509
$hash.results.height = 248
$hash.results.location = New-Object System.Drawing.Point(14, 162)
$hash.results.Font = New-Object System.Drawing.Font('Lucida Console', 8)
$hash.results.ForeColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")
$hash.results.ReadOnly = $True

$hash.progressbar1 = New-Object System.Windows.Forms.ProgressBar
$hash.progressbar1.width = 508
$hash.progressbar1.height = 10
$hash.progressbar1.location = New-Object System.Drawing.Point(14, 413)
#$hash.progressbar1.Style = "Marquee"
$hash.progressbar1.Style = "Continuous"
$hash.progressbar1.MarqueeAnimationSpeed = 20
#$hash.progressbar1.Hide()
#$hash.progressbar1.Visible = $false

$hash.label1 = New-Object system.Windows.Forms.Label
$hash.label1.text = "Waiting..."
$hash.label1.AutoSize = $false
$hash.label1.width = 200
$hash.label1.height = 15
$hash.label1.location = New-Object System.Drawing.Point(28, 424)
$hash.label1.Font = New-Object System.Drawing.Font('Calibri', 8, [System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))
$hash.label1.ForeColor = 'red'
$hash.label1.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")
#$hash.label1.Hide()
#$hash.label1.Visible = $false

$hash.disclaimer = New-Object system.Windows.Forms.TextBox
$hash.disclaimer.multiline = $true
$hash.disclaimer.text = "BLA BLA BLA BLA BLA BLA"
$hash.disclaimer.width = 429
$hash.disclaimer.height = 20
$hash.disclaimer.location = New-Object System.Drawing.Point(53, 442)
$hash.disclaimer.Font = New-Object System.Drawing.Font('Calibri', 10, [System.Drawing.FontStyle]([System.Drawing.FontStyle]::Bold))
$hash.disclaimer.ForeColor = [System.Drawing.ColorTranslator]::FromHtml("#ff0000")
$hash.disclaimer.BackColor = [System.Drawing.ColorTranslator]::FromHtml("#000000")

$hash.form.controls.AddRange(@($hash.okla_logo, $hash.aao_logo, $hash.exit_button, $hash.start_button, $hash.results, $hash.disclaimer, $hash.progressbar1, $hash.label1))

$hash.start_button.Add_Click({ RunAppCode })

$hash.exit_button.Add_Click({ closeForm
        $hash.Form.Tag = $hash.Form.close()
        #$script:powershell.EndInvoke($script:handle)
        #$script:powershell.Close()
        #$script:powershell.Dispose()
        #$script:runspace.Close()
        #$script:runspace.Dispose()
        #[System.GC]::Collect()
    })

$formresult = $hash.Form.ShowDialog()

if ($formresult -eq [System.Windows.Forms.DialogResult]::Cancel) {
    Exit
}

#Region Logic 
##All done!
#endregion
powershell winforms download progress-bar runspace
© www.soinside.com 2019 - 2024. All rights reserved.