【问题标题】:Powershell calling psexec, script will halt until psexec is done, need to break this by timePowershell 调用 psexec,脚本将停止,直到 psexec 完成,需要按时打破
【发布时间】:2021-05-22 14:14:57
【问题描述】:

我有以下代码:

foreach ($program in $programlist){
        "$line installed $program" | Out-File "$logpath\log.txt" -Append

        psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "pushd $BucketPath & copy $program c:\programdata\"
        psexec \\"$hostikname" -i -u bla\bla -p $plainpwd -h cmd /c  "c:\programdata\$program"
        psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "del c:\programdata\$program"
       
       }

这是我们用来在客户端电脑上远程安装程序的脚本的一部分。 效果很好只有一个问题: 脚本在完成每个 psexec 行之前不会继续。该脚本让最终用户以管理员权限安装程序,它是交互式安装,因此需要用户在计算机上。 如果由于某种原因一个用户调用脚本,然后去喝咖啡,脚本将一直卡住,直到用户返回并继续安装。 我想做的是检查 - 如果由于某种原因其中一条 psexec 行花费超过 2 分钟,我想退出 break break psexec 部分并继续代码。

我怎样才能做到这一点?

【问题讨论】:

  • 您可以使用start-job 不等待任何人
  • 不幸的是,这对脚本不利,因为一个 psexec 行依赖于另一个,主要目标是等待 X 分钟,如果脚本发现某些东西卡在其中一个psexec 行我想让它做点什么
  • do until 循环怎么样?
  • $TimeStart = Get-Date $TimeEnd = $timeStart.addminutes(2) Write-Host "Start Time: $TimeStart" write-host "End Time: $TimeEnd" Do { $TimeNow = Get-Date if ($TimeNow -ge $TimeEnd) { Write-host "It's time to finish." } else { Write-Host "Not done yet, it's only $TimeNow" } Start-Sleep -Seconds 10 } Until ($TimeNow -ge $TimeEnd)
  • psexec 将在远程计算机上打开安装,发生这种情况时,脚本将在远程计算机上安装完成后继续执行,如果远程计算机上的用户不执行任何操作,则意味着安装将在远程计算机上停止,然后脚本不会继续前进。即使最终用户不在他的计算机上,我也需要找到一种在 X 分钟后继续前进的方法。就像 psexec 脚本块的计时器一样。 10 分钟后,打破障碍并继续

标签: powershell break psexec


【解决方案1】:

正如Abraham 提到的,Start-Job 是解决您问题的可行方案。使用 Start-Job 将允许您启动和监控作业的进度/状态。

    $allowedSecondsForCompletion = 120
    foreach ($program in $programlist) {
        "$line installed $program" | Out-File "$logpath\log.txt" -Append
    
        $timer = [System.Diagnostics.Stopwatch]::StartNew()
        $job = Start-Job -ScriptBlock {  
            psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "pushd $BucketPath & copy $program c:\programdata\"
            psexec \\"$hostikname" -i -u bla\bla -p $plainpwd -h cmd /c "c:\programdata\$program"
            psexec \\"$hostikname" -u bla\bla -p $plainpwd cmd /c "del c:\programdata\$program"
        }
        
        while ($job.state -eq 'Running' -and $timer.ElapsedMilliseconds -lt ($allowedSecondsForCompletion * 1000))
        {
            start-sleep -Seconds 5
        }
    
        if ($job.State -ne 'Completed') {
            # check and Log failure
            
            # Terminate job if still running
            $job | Remove-Job -Force
            # or $job.StopJob()

        }
       
    }

【讨论】:

  • 我建议添加$job | Remove-Job以防作业成功完成,$job | Remove-Job -Force以防超时,因此作业将被强制终止。
  • 在答案中添加了@zett42 的建议。谢谢zett42。