Timothy Liu
Timothy Liu

Reputation: 31

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

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

Answers (2)

Victor Fialkin
Victor Fialkin

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

user4003407
user4003407

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

Related Questions