n0rd
n0rd

Reputation: 12670

What exactly does the call operator in PowerShell do?

I have a powershell script that runs some executable using call operator. Something like this:

$executable = 'c:\dev\test.exe'
& $executable | Out-Host
Write-Host 'done'

That test.exe in turn runs another programs (server.exe) and communicates with it over TCP/IP (this program requires administrative privileges and because of that my powershell script is run as admin), also it runs trivial batch script (which runs and terminates in 1 second). Once started, server.exe runs until terminated by test.exe. All programs involved are console applications. Another fact probably worth noting is that since server.exe requires admin privileges it runs in separate console window than test.exe.

Sometimes test.exe does not terminate server.exe (sometimes due to crash, sometimes due to bugs in it). When this happens, after test.exe termination execution does not return to powershell script (I don't see 'done' being printed). If I terminate server.exe manually, I immediately see 'done' in the powershell console. Why is this happening? Why powershell waits for process to terminate which it had not started and which does not even run in the same console?

In my investigation attempts I tried to reproduce the issue with less amount of code involved I created test2.exe which simply runs server.exe (exactly the same way, I have access to test.exe sources) and terminates. Now when I run the same powershell script but with test2.exe as $executable, I see exactly what I expected to see initially: server.exe starts in separate window, then 'done' is printed in powershell window (and powershell script terminates) while server.exe still runs.

I watched Process Explorer while test.exe run and I am sure no other process besides server.exe are running after test.exe termination.

I failed to find any in-depth explanation what & operator does and what it waits for, maybe you have some ideas?

Update: Instead of running with call operator I tried Start-Process:

$executable = 'c:\dev\test.exe'
Start-Process $executable -Wait
Write-Host 'done'

Now test.exe runs in it's own console, terminates and powershell still waits for server.exe to finish.

Also I tried to run the batch script:

c:\dev\test.exe
echo done

and it works fine: as soon as test.exe terminates 'done' is printed to console and batch file stops (server.exe is still running).

Another update: changed script to do the following:

$executable = 'c:\dev\test.exe'
$proc = Start-Process $executable -PassThru
do {
   Get-Process -Id $proc.Id
   Start-Sleep -Seconds 10
} while ($true)

I am getting the regular Get-Process output few times while test.exe is running then (after test.exe terminates) it starts producing "Cannot find process with the process identifier 3028" errors. So I probably can go this way.

Another thing I tried was:

$env:PATH += ';c:\dev\;'
test.exe
Write-Host 'done'

Still, no luck: test.exe terminates, powershell still waits for server.exe to terminate.

Tried the job approach, too:

$job = Start-Job {& 'c:\dev\test.exe'}
do
{
    $job
    Start-Sleep -Seconds 10
} while ($job.JobStateInfo.State -eq [System.Management.Automation.JobState]::Running)

Receive-Job $job

It never quits unless I terminate server.exe.

Upvotes: 5

Views: 4046

Answers (1)

Keith Hill
Keith Hill

Reputation: 201992

The call operator & simply attempts invoke the named command (application, script, function, cmdlet) following it, passing any additional arguments to the command. In addition, & executes the command in a new scope whereas the . executes the command in the current scope. When executing an application (exe) I don't think it matters that you execute in a new scope. The exe can't impact scoped variables in PowerShell.

WRT the test.exe behavior, PowerShell won't return control to the script until a console exe finishes. Test.exe and test2.exe are both console subsystem exes right? PowerShell behaves differently with Windows subsystem exes. It launches them and returns immediately unless you use a trick like this notepad.exe | Out-Null.

Upvotes: 6

Related Questions