powershell Gui进度条与批处理文件

时间:2015-04-15 18:10:41

标签: user-interface powershell batch-file

我在另一个网站上找到了这个gui进度条。它解释的方式,应该解决我的问题,当工作运行时不要让gui冻结。

然而,由于我处理批处理文件(安装应用程序),我需要做一个foreach应用程序并逐个安装它们,而不是让gui冻结。

以下是网站link

的链接
EDIT: UPDATE the SCRIPT. so far this works but all batch files install at the same time which is causing them to fail. I have more applications but for testing I just added 3. 

我只是假设$ job没有将其状态传递给" updatescript"和#34; completedscript"

$Appname = @("Adobe_FlashPlayer", "Acrobat_Reader, "Microsoft_RDP_8.1")

$formJobProgress_Load={
#TODO: Initialize Form Controls here
$timer1.Interval = 1000
$timer1.Tag = 0
$timer1.Start()
[System.Windows.Forms.Application]::DoEvents()
}

$formMain_FormClosed=[System.Windows.Forms.FormClosedEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.FormClosedEventArgs]
#Stop any pending jobs
Stop-JobTracker
}

$timerJobTracker_Tick={
Update-JobTracker   
}
#region Job Tracker
$JobTrackerList = New-Object System.Collections.ArrayList
function Add-JobTracker
{

Param (
    #[ValidateNotNull()]
    #[Parameter(Mandatory = $true)]
    [string]$Name,
    #[ValidateNotNull()]
    #[Parameter(Mandatory = $true)]
    [ScriptBlock]$CompletedScript,
    [ScriptBlock]$UpdateScript,
    [ScriptBlock]$JobScript,
    $ArgumentList = $null)

    $job = Start-Job -ScriptBlock $JobScript -ArgumentList $ArgumentList





if($job -ne $null)
{
    #Create a Custom Object to keep track of the Job & Script Blocks
    $psObject = New-Object System.Management.Automation.PSObject

    Add-Member -InputObject $psObject -MemberType 'NoteProperty' -Name Job      -Value $job
    Add-Member -InputObject $psObject -MemberType 'NoteProperty' -Name CompleteScript  -Value $CompletedScript
    Add-Member -InputObject $psObject -MemberType 'NoteProperty' -Name UpdateScript  -Value $UpdateScript

    [void]$JobTrackerList.Add($psObject)    

    #Start the Timer
    if(-not $timerJobTracker.Enabled)
    {
        $timerJobTracker.Start()
    }
}
elseif($CompletedScript -ne $null)
{
    #Failed
    Invoke-Command -ScriptBlock $CompletedScript -ArgumentList $null
}

}
function Update-JobTracker
{
<#
    .SYNOPSIS
        Checks the status of each job on the list.
#>

#Poll the jobs for status updates
$timerJobTracker.Stop() #Freeze the Timer

for($index =0; $index -lt $JobTrackerList.Count; $index++)
{
    $psObject = $JobTrackerList[$index]

    if($psObject -ne $null) 
    {
        if($psObject.Job -ne $null)
        {
            if($psObject.Job.State -ne "Running")
            {               
                #Call the Complete Script Block
                if($psObject.CompleteScript -ne $null)
                {
                    #$results = Receive-Job -Job $psObject.Job
                    Invoke-Command -ScriptBlock $psObject.CompleteScript -   ArgumentList $psObject.Job
                }

                $JobTrackerList.RemoveAt($index)
                Remove-Job -Job $psObject.Job
                $index-- #Step back so we don't skip a job
            }
            elseif($psObject.UpdateScript -ne $null)
            {
                #Call the Update Script Block
                Invoke-Command -ScriptBlock $psObject.UpdateScript -ArgumentList $psObject.Job
            }
        }
    }
    else
    {
        $JobTrackerList.RemoveAt($index)
        $index-- #Step back so we don't skip a job
    }
}

if($JobTrackerList.Count -gt 0)
{
    $timerJobTracker.Start()#Resume the timer   
}   
}
function Stop-JobTracker
{
<#
    .SYNOPSIS
        Stops and removes all Jobs from the list.
#>
#Stop the timer
$timerJobTracker.Stop()

#Remove all the jobs
while($JobTrackerList.Count -gt 0)
{
    $job = $JobTrackerList[0].Job
    $JobTrackerList.RemoveAt(0)
    Stop-Job $job
    Remove-Job $job
}
}#endregion


$buttonStartJob_Click= {
$progressbaroverlay1.Value = 0
$progressbaroverlay1.Step = 1
$progressbaroverlay1.Maximum = $Appname.Count
$this.Enabled = $false
$buttonStartJob.Enabled = $false

#Create a New Job using the Job Tracker
foreach ($app in $Appname)
{
    $install = "C:\pstools\Update\cmd\$app\install.cmd"
    $run = "C:\Windows\System32\cmd.exe"
    Add-JobTracker -Name "test"`
                   -JobScript {
        param (
            [string]$batchFilePath
        )
        Write-Verbose "Launching: [$batchFilePath]" -Verbose
        Set-Location $env:windir
        & ($run, $batchFilePath)

    }` -ArgumentList $install -CompletedScript {

        Param ($Job)
        #$progressbar1.Value = 100
        #Enable the Button
        $ProgressBarOverlay1.PerformStep()
        $buttonStartJob.ImageIndex = -1
        $buttonStartJob.Enabled = $true
}`
    -UpdateScript {
        Param ($Job)
        $results = Receive-Job -Job $Job | Select-Object -Last 1

        if ($results -is [int])
        {
            $progressbaroverlay1.Value = $results
        }

    }
}
}
$timer1_Tick={

    #TODO: Place custom script here

    #if ([timespan]::FromSeconds($timerUpdate.Tag) -ge     [timespan]::Fromminutes(1))
    IF($progressbaroverlay1.Value -eq 100)
    {

        $timerUpdate.stop()
        $formSampleTimer.Close()
    }
    else
    {
        [System.Windows.Forms.Application]::DoEvents()
        $label1.Text = [timespan]::FromSeconds($timer1.Tag++)
    }

}

1 个答案:

答案 0 :(得分:0)

我假设您要么从某个地方复制它并将其修改为适合您的工作,或者您使用PowerGUI或Sapien之类的东西为您生成脚本,因为在我看来这很难读取代码。 / p>

如果我理解正确,您可以将$JobTrackerList创建为ArrayList个对象。然后,对于要安装的每个应用程序,向PSCustomObject添加ArrayList,其中包含3个属性,一个是在后台运行的Job,一个是在此时运行的脚本已完成,其中一个是更新进度条的脚本。因此每个对象都有一个正在运行的后台作业,这是此时的根本问题。但是等等,我们还没有完成,你有一个计时器正在运行(实际上没有在你给我们的代码中定义)运行,并且它停止的每1000个滴答,检查每个作业,如果它完成它运行& #34;完成&#34;您为该对象定义的scriptblock,然后从ArrayList中删除该对象。如果仍未完成,则使用&#34;更新&#34;更新进度条。脚本块。然后它再次启动计时器。

以下我认为需要发生的事情就像你想要的那样......你需要继续制作你的ArrayList,并为你想要的每个应用程序添加对象跑,但不要为他们创造就业机会!创建所有对象后,为第一个应用程序启动作业(并将其作为对象的成员添加,就像之前一样)。然后,当您的脚本检查已完成的作业时,在删除正在查看的对象之前,它应该为下一个对象启动作业。

所以,这需要重新编写代码。我不知道从哪里开始这个,因为你所拥有的代码与我编写代码的方式非常不同,所以我已经给了你我的建议,现在我来了让你从这里运行它。如果您需要帮助编写代码(至少先尝试一下),请告诉我,我会看到我能做些什么。可能不是今天,我已经厌倦了,而不是在我的A游戏中,但是如果你最终需要帮助,我相信明天我能拿出一些东西。

编辑:好的,我认为我的代码可以做你想做的事情,并使用你现有的代码:

$formJobProgress_Load={
    #TODO: Initialize Form Controls here
    $timer1.Interval = 1000
    $timer1.Tag = 0
    $timer1.Start()
    [System.Windows.Forms.Application]::DoEvents()
}

$timerJobTracker_Tick={
    $timerJobTracker.Stop() #Freeze the Timer
    for($index =0; $index -lt $JobTrackerList.Count; $index++){
        $psObject = $JobTrackerList[$index]
        if($psObject -ne $null -AND $psObject.Job -ne $null -AND $psObject.Job.State -ne "Running"){
            #Perform old 'Complete' scriptblock to update progressbar
            $ProgressBarOverlay1.PerformStep()

            #Check if this is the only job, and if not start the next one
            If($JobTrackerList.count -gt 1){
                $NextJob = $JobTrackerList[($index+1)]
                $NextJob.Job = Start-Job -ScriptBlock $NextJob.JobScript
            }
            $JobTrackerList.RemoveAt($index)
            Remove-Job -Job $psObject.Job
            $index-- #Step back so we don't skip a job
        }Else{
            $results = Receive-Job -Job $Job | Select-Object -Last 1
            if ($results -is [int]){
                $progressbaroverlay1.Value = $results
            }
        }
    }

    if($JobTrackerList.Count -gt 0){
        $timerJobTracker.Start()#Resume the timer   
    }
}

$formMain_FormClosed=[System.Windows.Forms.FormClosedEventHandler]{
    #Stop the timer
    $timerJobTracker.Stop()

    #Remove all the jobs
    while($JobTrackerList.Count -gt 0){
        $job = $JobTrackerList[0].Job
        $JobTrackerList.RemoveAt(0)
        Stop-Job $job
        Remove-Job $job
    }
}


$Appname = @("Adobe_FlashPlayer", "Acrobat_Reader", "Microsoft_RDP_8.1")

$JobTrackerList = New-Object System.Collections.ArrayList

$buttonStartJob_Click= {
    $progressbaroverlay1.Value = 0
    $progressbaroverlay1.Step = 1
    $progressbaroverlay1.Maximum = $Appname.Count
    $this.Enabled = $false
    $buttonStartJob.Enabled = $false

    ForEach($App in $Appname){

        $install = "C:\pstools\Update\cmd\$app\install.cmd"
        $run = "C:\Windows\System32\cmd.exe"
        $JobScript = {
            Write-Verbose "Launching: [$install]" -Verbose
            Set-Location $env:windir
            & $install
        }

        [void]$JobTrackerList.Add((New-Object PSObject -Property @{
            'Application' = $Name
            'JobScript' = $JobScript
            'Job' = $null
        }))
    }

    $JobTrackerList[0].Job = Start-Job -ScriptBlock $JobTrackerList[0].JobScript
}

$timer1_Tick={

    #TODO: Place custom script here

    #if ([timespan]::FromSeconds($timerUpdate.Tag) -ge     [timespan]::Fromminutes(1))
    IF($progressbaroverlay1.Value -eq 100)
    {

        $timerUpdate.stop()
        $formSampleTimer.Close()
    }
    else
    {
        [System.Windows.Forms.Application]::DoEvents()
        $label1.Text = [timespan]::FromSeconds($timer1.Tag++)
    }

}

我希望这适合你。