gpt4 book ai didi

powershell - 如何在执行静默安装时异步运行进度条?

转载 作者:行者123 更新时间:2023-12-02 23:25:47 27 4
gpt4 key购买 nike

目标:

我想在等待静默安装时异步运行进度条(显示耗时/估计时间)。例如,

RunWithProgressBar "cmd /c """" /Wait ""Setup.exe""" $(New-Timespan -Minutes 5)

最近的我来了:
## Functions

function global:BottleOfBeer {
$beer = $args[0]
if ($beer -eq 1) {
echo "$beer beer on the wall.";
} elseif ($beer -eq 0) {
echo "No beer left on the wall!";
} else {
echo "$beer beers left on the wall.";
}
sleep 1
}

function global:BeersOnTheWall {
$NumBeers = $args[0]
for ($i=$NumBeers; $i -ge 0; $i--) {
BottleOfBeer $i
}
}

function global:Install {
cmd /c @"
"AutoHotkey112306_Install.exe" /S /D="%cd%"
"@
}

function global:Uninstall {
cmd /c start "" /wait "Installer.ahk" /Uninstall
}

####START Progress Bar Stuff
function global:DisplayProgress {
$display = $args[0]
Write-Progress -Activity "Running..." -Status "$display"
}

function global:FormatDisplay {
$StartTime = $args[0]
$RunningTime = ($args[1]).Elapsed
$EstimatedTime = $args[2]
$RunningTimeDisplay = $([string]::Format("{0:d2}:{1:d2}:{2:d2}",
$RunningTime.hours,
$RunningTime.minutes,
$RunningTime.seconds))
$EstimatedEnd = $StartTime + $EstimatedTime
return $([string]::Format("(Start: {0}) (Elapsed/Estimated: {1}/{2}) (EstimatedEnd: {3})",
$StartTime.ToShortTimeString(),
$RunningTimeDisplay,
$EstimatedTime,
$EstimatedEnd.ToShortTimeString()))
}

function global:TearDownProgressBar {
$job = $args[0]
$event = $args[1]
$job,$event | Stop-Job -PassThru | Remove-Job #stop the job and event listener
Write-Progress -Activity "Working..." -Completed -Status "All done."
}

function RunWithProgressBar {
$Payload = $args[0]
$EstimatedTime = $args[1]

$global:StartTime = Get-Date
$global:RunningTime = [System.Diagnostics.Stopwatch]::StartNew()
$global:EstimatedTime = $EstimatedTime

$progressTask = {
while($true) {
Register-EngineEvent -SourceIdentifier MyNewMessage -Forward
$null = New-Event -SourceIdentifier MyNewMessage -MessageData "Pingback from job."
Start-Sleep -Seconds 1
}
}

$job = Start-Job -ScriptBlock $progressTask
$event = Register-EngineEvent -SourceIdentifier MyNewMessage -Action {
DisplayProgress $(FormatDisplay $global:StartTime $global:RunningTime $global:EstimatedTime)
}

try {
sleep 1
Invoke-Expression $Payload
} finally {
TearDownProgressBar $job $event
}
}
####END Progress Bar Stuff

## MAIN

RunWithProgressBar "BeersOnTheWall 2" $(New-Timespan -Seconds 3)
RunWithProgressBar "Install" $(New-Timespan -Seconds 30)
RunWithProgressBar "Uninstall" $(New-Timespan -Seconds 5)
RunWithProgressBar "BeersOnTheWall 2" $(New-Timespan -Seconds 3)

问题

尽管上述实现按预期运行,但只要 RunWithProgressBar 的有效载荷参数是一个更新进度条停止被触发的安装事件。

我在寻找什么:

如何修改我当前的实现以每秒更新进度条,即使在执行安装时也是如此?

最佳答案

我觉得你正试图在你的 RunWithProgressBar 中重新发明轮子功能:

 $progressTask = {
while($true) {
Register-EngineEvent -SourceIdentifier MyNewMessage -Forward
$null = New-Event -SourceIdentifier MyNewMessage -MessageData "Pingback from job."
Start-Sleep -Seconds 1
}
}

$job = Start-Job -ScriptBlock $progressTask
$event = Register-EngineEvent -SourceIdentifier MyNewMessage -Action {
DisplayProgress $(FormatDisplay $global:StartTime $global:RunningTime $global:EstimatedTime)
}

这基本上是一个 计时器 并且可以重构:
$timer = new-object timers.timer     
$action = {DisplayProgress $(FormatDisplay $global:StartTime $global:RunningTime $global:EstimatedTime)}
$timer.Interval = 1000
Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier thetimer -Action $action | out-null
$timer.Start()

但是,要解决您的问题,您可以在作业中执行任务并等待它们完成。

与其将函数公开,不如考虑在 scriptblock 中定义它们。 :
$initializationScriptBlock = {
$functions = @{
Install = {
cmd /c '"AutoHotkey112306_Install.exe" /S /D="%cd%"'
}

BottleOfBeer = {
$beer = $args[0]
if ($beer -eq 1) {
echo "$beer beer on the wall.";
} elseif ($beer -eq 0) {
echo "No beer left on the wall!";
} else {
echo "$beer beers left on the wall.";
}
sleep 1
}

BeersOnTheWall = {
$NumBeers = $args[0]
for ($i=$NumBeers; $i -ge 0; $i--)
{
BottleOfBeer $i
}
}

Uninstall = {
cmd /c start "" /wait "Installer.ahk" /Uninstall
}
}
}

现在,而不是 Invoke-Expression $Payload您通过 initializationScriptBlock 开始新工作和实际功能 $functionToExecute作为 scriptblock执行:
$executingJob =  start-Job -InitializationScript $initializationScriptBlock -ScriptBlock $functionToExecute 
while ((Get-job $executingJob.Id).State -eq 'Running')
{
sleep 1;
}

您的 RunWithProgressBar现在使用 PowerShell 的函数-like函数定义:
function RunWithProgressBar 
{
Param(
[Parameter(Mandatory=$true, Position=0)]
[scriptblock]$functionToExecute,

[Parameter(Mandatory=$true, Position=1)]
[timespan]$EstimatedTime
)
....
}

请考虑更改脚本的其余部分以提高可读性。

要调用带有进度条的函数,首先必须加载 initializationScriptBlock到当前运行空间:
. $initializationScriptBlock

现在您可以像这样调用函数:
RunWithProgressBar $functions.BottleOfBeer (New-Timespan -Seconds 3)
RunWithProgressBar $functions.Install (New-Timespan -Seconds 30)

您的整个脚本现在看起来像这样:
## Functions
$initializationScriptBlock = {
$functions = @{

Install = {
Sleep 5
<#cmd /c @"
"AutoHotkey112306_Install.exe" /S /D="%cd%"
"@#>
}

BottleOfBeer = {
$beer = $args[0]
if ($beer -eq 1) {
echo "$beer beer on the wall.";
} elseif ($beer -eq 0) {
echo "No beer left on the wall!";
} else {
echo "$beer beers left on the wall.";
}
sleep 1
}

BeersOnTheWall = {
$NumBeers = $args[0]
for ($i=$NumBeers; $i -ge 0; $i--)
{
BottleOfBeer $i
}
}

Uninstall = {
cmd /c start "" /wait "Installer.ahk" /Uninstall
}

}

}

####START Progress Bar Stuff
function global:DisplayProgress {
$display = $args[0]
Write-Progress -Activity "Running..." -Status "$display"
}

function global:FormatDisplay {
$StartTime = $args[0]
$RunningTime = ($args[1]).Elapsed
$EstimatedTime = $args[2]
$RunningTimeDisplay = $([string]::Format("{0:d2}:{1:d2}:{2:d2}",
$RunningTime.hours,
$RunningTime.minutes,
$RunningTime.seconds))
$EstimatedEnd = $StartTime + $EstimatedTime
return $([string]::Format("(Start: {0}) (Elapsed/Estimated: {1}/{2}) (EstimatedEnd: {3})",
$StartTime.ToShortTimeString(),
$RunningTimeDisplay,
$EstimatedTime,
$EstimatedEnd.ToShortTimeString()))
}


function RunWithProgressBar
{
Param(
[Parameter(Mandatory=$true, Position=0)]
[scriptblock]$functionToExecute,

[Parameter(Mandatory=$true, Position=1)]
[timespan]$EstimatedTime
)

$global:StartTime = Get-Date
$global:RunningTime = [System.Diagnostics.Stopwatch]::StartNew()
$global:EstimatedTime = $EstimatedTime


$timer = new-object timers.timer

$action = {DisplayProgress $(FormatDisplay $global:StartTime $global:RunningTime $global:EstimatedTime)}
$timer.Interval = 1000

Register-ObjectEvent -InputObject $timer -EventName elapsed –SourceIdentifier thetimer -Action $action | out-null

$timer.Start()

try {
$executingJob = start-Job -InitializationScript $initializationScriptBlock -ScriptBlock $functionToExecute
while ((Get-job $executingJob.Id).State -eq 'Running')
{
sleep 1;
}

} finally {
$timer.stop()

Unregister-Event thetimer
}
}
####END Progress Bar Stuff

## MAIN
. $initializationScriptBlock

RunWithProgressBar $functions.BottleOfBeer (New-Timespan -Seconds 3)
RunWithProgressBar $functions.Install (New-Timespan -Seconds 30)
RunWithProgressBar $functions.Uninstall (New-Timespan -Seconds 5)
RunWithProgressBar $functions.BeersOnTheWall (New-Timespan -Seconds 3)

你的脚本现在应该可以工作了,即使还有很多需要重构的地方。 G。函数名、作用域

回复您的评论:

1.) 您可以使用 Receive-Job在循环中检索输出:
$executingJob =  start-Job -InitializationScript $initializationScriptBlock -ScriptBlock $functionToExecute
while ((Get-job $executingJob.Id).State -eq 'Running')
{
Receive-Job $executingJob.Id
sleep 1;
}
Receive-Job $executingJob.Id

2.)
执行 $initializationScriptBlock 后使用:
. $initializationScriptBlock

您可以使用任何功能:
& $functions.BottleOfBeer

关于powershell - 如何在执行静默安装时异步运行进度条?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37324882/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com