Code in Job's Script Block after Start-Process Does not Execute

こ雲淡風輕ζ 提交于 2019-12-02 01:41:18

问题


When I create a automation script with PowerShell 5.1, I got an issue – in a script block of a job, the code after Start-Process will not get chance to execute. Here’s a simple repro:

Step 1 >> Prepare a .cmd file for Start-Process, the code in callee.cmd is:

@echo off
echo "Callee is executing ..."
exit /B 0

Step 2 >> Prepare the PowerShell code,

$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)

Step 3 >> Run the PowerShell script, the output on screen is:

Id     Name            PSJobTypeName   State         HasMoreData     Location             Command
--     ----            -------------   -----         -----------     --------             -------
1      Job1            BackgroundJob   Completed     True            localhost            ...
Completed

The expected value should be “Failed”. Does my code have problem or I’m using jobs in a wrong way?


回答1:


Start-Job run job in separate PowerShell process in so-called server mode. In this mode PowerShell job process use standard input and output streams to exchange messages with the parent process.

-NoNewWindow parameter of Start-Process cmdlet instruct it to connect spawned console child process to the standard streams of its parent.

Thus, using Start-Process -NoNewWindow inside of PowerShell job, you connect spawned cmd.exe process to the same streams, which PowerShell job process use to exchange messages with its own parent process.

Now, when spawned cmd.exe write something into its standard output stream, it disturb normal message exchange between PowerShell job process and its parent, which leads to some unexpected behavior.




回答2:


PetSerAl gave a great explanation of why it happens but it took me while to find a proper solution.

First thing - as some people mentioned don't use -NoNewWindow, use -WindowStyle Hidden instead.

Second, output results to file and handle them in your script block. There are two parameters, one for output and another for errors -RedirectStandardOutput and -RedirectStandardError. For some reasons I was sure that first one will handle all output and my code worked well if there were no errors, but was failing with no output in case of exceptions in script block.

I created a function that also handles process status result:

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
 }         
}


来源:https://stackoverflow.com/questions/45764330/code-in-jobs-script-block-after-start-process-does-not-execute

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!