Discussion:
Executing external program - foreground and background
(too old to reply)
Scott Bass
2012-02-22 04:05:25 UTC
Permalink
(Hoping to get an answer here...)

Summary:
See http://social.technet.microsoft.com/Forums/en-AU/winserverpowershell/thread/7135b7bb-ef90-4c17-8170-ff3aaae8cfa9.

Details:
Try this:

1. Create a .bat or .cmd file that returns a non-zero return code. I
called mine error.cmd.

@exit 123


2. Create the below script. $cmd is the path to where you created
error.cmd:

# specify path to dummy batch file that returns non-zero exit code
$cmd="$env:userprofile\My Documents\My Powershell Scripts\error.cmd"

# invoke using cmd / c - this works
cmd /c " ""$cmd"" "
"LastExitCode=$LastExitCode"

# "reset" LastExitCode
$LastExitCode=999

# invoke using Start-Process - this does not work
Start-Process $cmd -Wait
"LastExitCode=$LastExitCode"


Execute this script. When I invoke error.cmd via cmd /c, it works,
i.e. $LastExitCode has the correct value. When I invoke error.cmd via
Start-Process, $LastExitCode does not have the correct value.

I thought the whole idea of PowerShell was to replace the ancient and
klunky cmd.exe. (Ok, it's not the "whole idea", but hopefully you get
what I mean without arguing semantics).

Sooooo...can I:

1) Invoke an external command without using cmd.exe (via Start-
Process, Invoke-Command, Invoke-Expression, whatever)

2) Pause the script until that command finishes

3) Have the correct value of $LastExitCode based on the return code
(%ERRORLEVEL%) from the invoked external command?

Thanks,
Scott
naugiedoggie
2012-02-25 15:42:10 UTC
Permalink
Post by Scott Bass
(Hoping to get an answer here...)
Seehttp://social.technet.microsoft.com/Forums/en-AU/winserverpowershell/....
1.  Create a .bat or .cmd file that returns a non-zero return code.  I
called mine error.cmd.
@exit 123
2.  Create the below script.  $cmd is the path to where you created
# specify path to dummy batch file that returns non-zero exit code
$cmd="$env:userprofile\My Documents\My Powershell Scripts\error.cmd"
# invoke using cmd / c - this works
cmd /c " ""$cmd"" "
"LastExitCode=$LastExitCode"
# "reset" LastExitCode
$LastExitCode=999
# invoke using Start-Process - this does not work
Start-Process $cmd -Wait
"LastExitCode=$LastExitCode"
Execute this script.  When I invoke error.cmd via cmd /c, it works,
i.e. $LastExitCode has the correct value.  When I invoke error.cmd via
Start-Process, $LastExitCode does not have the correct value.
I thought the whole idea of PowerShell was to replace the ancient and
klunky cmd.exe.  (Ok, it's not the "whole idea", but hopefully you get
what I mean without arguing semantics).
1) Invoke an external command without using cmd.exe (via Start-
Process, Invoke-Command, Invoke-Expression, whatever)
2) Pause the script until that command finishes
3) Have the correct value of $LastExitCode based on the return code
(%ERRORLEVEL%) from the invoked external command?
Thanks,
Scott
Hello,

It seems to me that Start-Job, Get-Job and Receive Job provide the
control of the (background) processes that you are looking for.

"Exit code" is somewhat outmoded in the PS environment. If it's
really needed, then you will have to wrap the exe calls in PS scripts
or functions that would capture it and return it to the calling shell;
then run these scripts via Start-Job.

For exits that really are errors, you could create your own
ErrorDetail object, onto which you could add an 'ExitCode' property,
and return that. This then would be available in the calling shell
via the $error object reference.

It's pretty hard to script any complex tasks in PS when you're just
passing back a bit of text like the value of $LASTEXITCODE. Another
option might be:

$job = Get-Job -Name "ReallyImportantJob" | Select-Object
Name,Id,State,ExitCode

while($job.State -eq "Running"){
$drinkmorecoffee = "yes"
}
# after $job.State = "Failed" or $job.State = "Completed"
$job.ExitCode = $LASTEXITCODE

There is no "ExitCode" property on the job object returned by Get-Job,
but happily, Select-Object will silently add it to the new object
created for the $job reference.
(Note that in PS, it is possible to modify directly object types, via
the Adaptive Type System. Thus, on the system on which you run your
scripts, you could modify the System.Management.Automation.Job object
to include a custom property, ExitCode.)

Your wrapper scripts return the $job objects instead of just the exit
code.

If you collect all these $job objects (in another object, presumably),
you now can process them according to your exit codes using the
standard PS pipelines. e.g.,

$joblist.JOBS = @($job,$job,$job,$job)
$joblist.JOBS | %{ if($_.ExitCode -eq 0 {#do something here}
elseif($_.ExitCode -eq 20){#do something different here}}

Yes, polling a job state in a while loop can be very expensive but
it's uncomplicated and easy for a half-dozen or so jobs.

Thanks.

mp
c***@gmail.com
2016-08-04 12:20:30 UTC
Permalink
Hello Scott

did you finally find solution? I am facing similar problem spawning single job in the background i.e. tool.exe (or tool.cmd) which returns ERRORLEVEL code.

while ($job.State -eq "running") {blabla}
$Result = Receive-Job $job

but $LASTEXITCODE or $Result won't contain correct ERRORLEVEL value.
Post by Scott Bass
(Hoping to get an answer here...)
See http://social.technet.microsoft.com/Forums/en-AU/winserverpowershell/thread/7135b7bb-ef90-4c17-8170-ff3aaae8cfa9.
1. Create a .bat or .cmd file that returns a non-zero return code. I
called mine error.cmd.
@exit 123
2. Create the below script. $cmd is the path to where you created
# specify path to dummy batch file that returns non-zero exit code
$cmd="$env:userprofile\My Documents\My Powershell Scripts\error.cmd"
# invoke using cmd / c - this works
cmd /c " ""$cmd"" "
"LastExitCode=$LastExitCode"
# "reset" LastExitCode
$LastExitCode=999
# invoke using Start-Process - this does not work
Start-Process $cmd -Wait
"LastExitCode=$LastExitCode"
Execute this script. When I invoke error.cmd via cmd /c, it works,
i.e. $LastExitCode has the correct value. When I invoke error.cmd via
Start-Process, $LastExitCode does not have the correct value.
I thought the whole idea of PowerShell was to replace the ancient and
klunky cmd.exe. (Ok, it's not the "whole idea", but hopefully you get
what I mean without arguing semantics).
1) Invoke an external command without using cmd.exe (via Start-
Process, Invoke-Command, Invoke-Expression, whatever)
2) Pause the script until that command finishes
3) Have the correct value of $LastExitCode based on the return code
(%ERRORLEVEL%) from the invoked external command?
Thanks,
Scott
Loading...