Powershell -- cascading exit codes through nested shells
Finally resolved why I couldn't repro the issue in this cut down case; so, for future reference, just the real problem, and none of the dead ends:
I have a problem. I want to run a set of PowerShell scripts from an orchestrating PowerShell script, each in their own process so that I can relinquish assemblies that they've Add-Type
d quickly, and thus allow them to be updated when I re-deploy the whole system. And those scripts can potentially fail for some reasons, and the failure can be soft (retry with different parameters) or hard (abort entirely).
Plus, I don't want to capture the (write-)output of the inner scripts as I want to watch their progress; which leaves me with the exit code as mechanism, which is enough for my need.
We can test this mechanism with a simple script that we can make fail on demand:
And drive it like
This results in
PS> $LASTEXITCODE 0 PS> .\OuterScript.ps1 output host 01 December 2014 17:34:50 Inner script done Got file code 0 output host 01 December 2014 17:34:52 Inner script done Got file code 23 PS> $LASTEXITCODE 23
However, if I add in one line (the one with the comment):
We get
PS> $LASTEXITCODE 23 PS> $LASTEXITCODE = 0 PS> $LASTEXITCODE 0 PS> .\OuterScript.ps1 output host 01 December 2014 17:36:14 Inner script done Got file code 0 output host 01 December 2014 17:36:15 Inner script done Got file code 0 output host 01 December 2014 17:36:17 Inner script done Got file code 0 PS> $LASTEXITCODE 0 PS>
we get bitten by PowerShell's odd behaviour regarding automatic variables, which makes the local use of the name somehow refer to a different (and locally overriding) thing to what gets set by process exit -- another variation on the gotcha I hit a couple of years ago.
What I'd been hitting was just that explicit zeroing of the exit code (in a dense block of initialisations, where I'd not spotted it) had been happening, before a process launch and completion had created the "real" $LASTEXITCODE
. Remove that line, leave the value unset on start, and it all just works.