当我使用PowerShell 5.1创建自动化脚本时,我遇到了一个问题 - 在作业的脚本块中,Start-Process之后的代码将无法执行。这是一个简单的复制品:
步骤1>>为Start-Process准备一个.cmd文件,callee.cmd中的代码是:
@echo off
echo "Callee is executing ..."
exit /B 0
第2步>>准备PowerShell代码
$scriptBlock = {
$res = Start-Process -FilePath "cmd.exe" -Wait -PassThru -NoNewWindow -ArgumentList "/c .\callee.cmd"
throw "ERROR!"
}
$job = Start-Job -ScriptBlock $scriptBlock
Wait-Job $job
Receive-Job $job
Write-Host($job.State)
步骤3>>运行PowerShell脚本,屏幕上的输出为:
Id Name PSJobTypeName State HasMoreData Location Command
-- ---- ------------- ----- ----------- -------- -------
1 Job1 BackgroundJob Completed True localhost ...
Completed
预期值应为“失败”。 我的代码是否有问题或我以错误的方式使用作业?
答案 0 :(得分:3)
Start-Job
在所谓的服务器模式中的单独PowerShell进程中运行作业。在此模式下,PowerShell作业进程使用标准输入和输出流与父进程交换消息。
-NoNewWindow
cmdlet的 Start-Process
参数指示它将生成的控制台子进程连接到其父级的标准流。
因此,在PowerShell作业中使用Start-Process -NoNewWindow
,您将生成的cmd.exe
进程连接到相同的流,PowerShell作业进程使用这些流与其自己的父进程交换消息。
现在,当生成cmd.exe
将某些内容写入其标准输出流时,会干扰PowerShell作业进程与其父进程之间的正常消息交换,从而导致一些意外行为。
答案 1 :(得分:1)
PetSerAl很好地解释了为什么会发生这种情况,但是花了我一些时间才找到合适的解决方案。
第一件事-正如某些人提到的不使用-NoNewWindow
,而是使用-WindowStyle Hidden
。
第二,将结果输出到文件并在脚本块中处理它们。有两个参数,一个用于输出,另一个用于错误-RedirectStandardOutput
和-RedirectStandardError
。
由于某些原因,我确定第一个将处理所有输出,并且如果没有错误,我的代码可以正常工作,但是如果脚本块中出现异常,则我的代码将失败并且没有输出。
我创建了一个还可以处理过程状态结果的函数:
function RunProcesSafe($pathToExe, $ArgumentList)
{
Write-Host "starting $pathToExe $ArgumentList"
$logFile = Join-Path $env:TEMP ([guid]::NewGuid())
$errorLogFile = Join-Path $env:TEMP ([guid]::NewGuid())
try
{
Write-Host "starting $pathToExe $ArgumentList"
$proc = Start-Process "$pathToExe" -Wait -PassThru -RedirectStandardError $errorLogFile -RedirectStandardOutput $logFile -WindowStyle Hidden -ArgumentList $ArgumentList
$handle = $proc.Handle
$proc.WaitForExit();
if ($proc.ExitCode -ne 0) {
Write-Host "FAILED with code:"+$proc.ExitCode
Throw "$_ exited with status code $($proc.ExitCode)"
}
}
Finally
{
Write-Host (Get-Content -Path $logFile)
Write-Host (Get-Content -Path $errorLogFile)
Remove-Item -Path $logFile -Force
Remove-Item -Path $errorLogFile -Force
}
}