Reputation: 31
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?
Upvotes: 3
Views: 2285
Reputation: 164
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
}
}
Upvotes: 1
Reputation: 22122
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.
Upvotes: 3