Closed paponius closed 5 years ago
You're more than welcome to submit changes as a pull request!
Unfortunately it seems that the story is even more complicated.
If the exit code is not zero then $?
is set to $false
; so far so good.
But other than that, it is very difficult to make any statements without being specific to the context / environment.
For example the code shown below will write some text to the error stream and exit with code 0 and 1 respectively:
$Error.Clear()
'Exit Code = 0 / Non-Redirected Error Stream'
cmd /c 'echo SomeErrorText 1>&2 && exit 0'
'$?: ' + $?
'$LASTEXITCODE: ' + $LASTEXITCODE
'$Error.Count: ' + $Error.Count
'-------------------------------------------'
$Error.Clear()
'Exit Code = 1 / Non-Redirected Error Stream'
cmd /c 'echo SomeErrorText 1>&2 && exit 1'
'$?: ' + $?
'$LASTEXITCODE: ' + $LASTEXITCODE
'$Error.Count: ' + $Error.Count
'-------------------------------------------'
Running it in the console (both PoSh 5.1 & 6.1) will result in the following output:
Exit Code = 0 / Non-Redirected Error Stream
SomeErrorText
$?: True
$LASTEXITCODE: 0
$Error.Count: 0
-------------------------------------------
Exit Code = 1 / Non-Redirected Error Stream
SomeErrorText
$?: False
$LASTEXITCODE: 1
$Error.Count: 0
-------------------------------------------
So the output on the error stream did not result in $?
being set to $false
.
This could change however when we run the same in another host like the ISE:
Exit Code = 0 / Non-Redirected Error Stream
cmd : SomeErrorText
At C:\temp\QuestionMarkVarOnErrStream.ps1:4 char:1
+ cmd /c 'echo SomeErrorText 1>&2 && exit 0'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (SomeErrorText :String) [], RemoteEx
ception
+ FullyQualifiedErrorId : NativeCommandError
$?: False
$LASTEXITCODE: 0
$Error.Count: 1
-------------------------------------------
Exit Code = 1 / Non-Redirected Error Stream
cmd : SomeErrorText
At C:\temp\QuestionMarkVarOnErrStream.ps1:13 char:1
+ cmd /c 'echo SomeErrorText 1>&2 && exit 1'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (SomeErrorText :String) [], RemoteEx
ception
+ FullyQualifiedErrorId : NativeCommandError
$?: False
$LASTEXITCODE: 1
$Error.Count: 1
-------------------------------------------
So this time the output on the error stream did result in $?
being set to $false
.
Finally if we start to redirect the error stream like so:
$Error.Clear()
'Exit Code = 0 / Redirected Error Stream'
cmd /c 'echo SomeErrorText 1>&2 && exit 0' 2> err.txt
'$?: ' + $?
'$LASTEXITCODE: ' + $LASTEXITCODE
'$Error.Count: ' + $Error.Count
'-------------------------------------------'
$Error.Clear()
'Exit Code = 1 / Redirected Error Stream'
cmd /c 'echo SomeErrorText 1>&2 && exit 1' 2> err.txt
'$?: ' + $?
'$LASTEXITCODE: ' + $LASTEXITCODE
'$Error.Count: ' + $Error.Count
'-------------------------------------------'
Then running it in the console (again both PoSh 5.1 and 6.1) will start creating error objects for output on this stream and it did result in $?
being set to $false
:
Exit Code = 0 / Redirected Error Stream
$?: False
$LASTEXITCODE: 0
$Error.Count: 1
-------------------------------------------
Exit Code = 1 / Redirected Error Stream
$?: False
$LASTEXITCODE: 1
$Error.Count: 1
-------------------------------------------
(Personal) Conclusion: Relying on $?
being set to $false
when $LASTEXITCODE
is not zero seems to be safe. The other way around is not always true and depends on other factors like the PoSh host and whether an error stream redirection are in place. For further details there is an issue with lots of details about PoSh error handling in general.
IMHO the best we can currently do is to add some hint about the fact that relying on $?
being set to $false
when $LASTEXITCODE
is not zero should be OK, but the other way around is not really reliable and should be tested within the given environment. Maybe I will come up with a small PR.
What do you think?
Go for it!
Sent from my iPhone
On Oct 5, 2018, at 1:12 PM, Aaron Kunz notifications@github.com<mailto:notifications@github.com> wrote:
Unfortunately it seems that the story is even more complicated. If the exit code is not zero then $? is set to $false; so far so good. But other than that, it is very difficult to make any statements without being specific to the context / environment.
For example the code shown below will write some text to the error stream and exit with code 0 and 1 respectively:
$Error.Clear()
'Exit Code = 0 / Non-Redirected Error Stream' cmd /c 'echo SomeErrorText 1>&2 && exit 0' '$?: ' + $? '$LASTEXITCODE: ' + $LASTEXITCODE '$Error.Count: ' + $Error.Count '-------------------------------------------'
$Error.Clear()
'Exit Code = 1 / Non-Redirected Error Stream' cmd /c 'echo SomeErrorText 1>&2 && exit 1' '$?: ' + $? '$LASTEXITCODE: ' + $LASTEXITCODE '$Error.Count: ' + $Error.Count '-------------------------------------------'
Running it in the console (both PoSh 5.1 & 6.1) will result in the following output:
So the output on the error stream did not result in $? being set to $false.
This could change however when we run the same in another host like the ISE:
Exit Code = 0 / Non-Redirected Error Stream cmd : SomeErrorText At C:\temp\QuestionMarkVarOnErrStream.ps1:4 char:1
+ CategoryInfo : NotSpecified: (SomeErrorText :String) [], RemoteEx
ception
+ FullyQualifiedErrorId : NativeCommandError
Exit Code = 1 / Non-Redirected Error Stream cmd : SomeErrorText At C:\temp\QuestionMarkVarOnErrStream.ps1:13 char:1
+ CategoryInfo : NotSpecified: (SomeErrorText :String) [], RemoteEx
ception
+ FullyQualifiedErrorId : NativeCommandError
So this time the output on the error stream did result in $? being set to $false.
Finally if we start to redirect the error stream like so:
$Error.Clear()
'Exit Code = 0 / Redirected Error Stream' cmd /c 'echo SomeErrorText 1>&2 && exit 0' 2> err.txt '$?: ' + $? '$LASTEXITCODE: ' + $LASTEXITCODE '$Error.Count: ' + $Error.Count '-------------------------------------------'
$Error.Clear()
'Exit Code = 1 / Redirected Error Stream' cmd /c 'echo SomeErrorText 1>&2 && exit 1' 2> err.txt '$?: ' + $? '$LASTEXITCODE: ' + $LASTEXITCODE '$Error.Count: ' + $Error.Count '-------------------------------------------'
Then running it in the console (again both PoSh 5.1 and 6.1) will start creating error objects for output on this stream and it did result in $? being set to $false:
(Personal) Conclusion: Relying on $? being set to $false when $LASTEXITCODE is not zero seems to be safe. The other way around is not always true and depends on other factors like the PoSh host and whether an error stream redirection are in place. For further details there is an issuehttps://github.com/PowerShell/PowerShell-Docs/issues/1583 with lots of details about PoSh error handling in general.
IMHO the best we can currently do is to add some hint about the fact that relying on $? being set to $false when $LASTEXITCODE is not zero should be OK, but the other way around is not really reliable and should be tested within the given environment. Maybe I will come up with a small PR.
What do you think?
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/devops-collective-inc/big-book-of-powershell-error-handling/issues/3#issuecomment-427485563, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AEpQ4uXRWD8Kqw8eJXm37WGgZS8V6NmSks5uh71FgaJpZM4T82Nk.
As mentioned on
It seems that $? is rather following a fact, if the external program produced an error, and not the exit code it provided.
Some programs do write all, or some non erroneous output to error stream, producing couple of entries in $Error variable. While still returns exit code 0
e.g.
REG IMPORT file.reg
produces output in error stream:$? is false $LASTEXITCODE is 0 $Error variable contains two new errors
Chocolatey guys run across this issue too and investigated further why: https://github.com/chocolatey/choco/issues/249#issuecomment-111645854
There are more programs, where I noticed this behavior in the past, but I didn't check the $? value there