3

Generally one can use $ErrorActionPreference to stop the execution of a PS script on error as in the example below that uses an invalid subversion command. The script exits after the first command.

$ErrorActionPreference='Stop'
svn foo
svn foo

Trying the same thing with the maven command (mvn.bat) executes both commands.

$ErrorActionPreference='Stop'
mvn foo
mvn foo

Initially I suspected that mvn.bat does not set an error code and PS just doesn't see the error. However, $? is set properly as demonstrated by the following, when PS exits after the first error:

mvn foo
if (-not $?) {exit 1}
mvn foo

So here's my question: Given that both svn.exe and mvn.bat set an error code on failure, why does the PS script not stop after the mvn error. I find it a lot more convenient to set "$ErrorActionPreference=Stop" globally rather than doing "if (-not $?) {exit 1}" after each command to terminate on error.

Bogdan Calmac
  • 7,993
  • 6
  • 51
  • 64

2 Answers2

2

Not all command line programs provide errors in the same way. Some set an exit code. Some don't. Some use the error stream, some don't. I've seen some command line programs actually output everything to error, and always output non-zero return codes.

So there's not a real safe guess one could ever make as to it having run successfully, and therefore it's next to impossible to codify that behavior into PowerShell.

$errorActionPreference will actually stop a script whenever a .exe writes to the error stream, but many .exes will write regular output to the console and never populate the error stream.

But it will not reliably work. Neither, for that matter, will $?. If an exe returns 0 and doesn't write to error $? will be true.

While it might be a pain in the butt to deal with each of these individual .exes and their errors in PowerShell, it's a great example of why PowerShell's highly structured Output/Error/Verbose/Warning/Debug/Progress streams and consistent error behavior in Cmdlets beats out plain old .EXE tools.

Hope this Helps

Start-Automating
  • 8,067
  • 2
  • 28
  • 47
  • Thanks, it helps. But in the same time I think the decision of the PS dev team to detect failure based on activity on the error stream was not very inspired. Since the beginning of time, programs return a non-zero exit code to signal an error. Maybe not every single program does that, but unix shell scripts work pretty well with this convention. This is not about how great PS is, but about how well it integrates with external programs. – Bogdan Calmac Jul 27 '11 at 00:50
  • I suggest you've not read the response. You would be amazed how unreliable exit codes, or even messages on the error stream, are. PowerShell does interpret a non-zero exit code as having failed. $? reflects this. It shouldn't stop the script altogether though, because that would mean that a single problem with any single piece of data would ALWAYS stop a bulk operation. This would make many more operations more difficult. – Start-Automating Aug 22 '11 at 04:34
  • 1
    I did read the response very carefully. But my point is still valid. If I set $errorActionPreference to "Stop" then I would expect PS to accomodate that. If you read my initial post, the script stops for svn.exe (probably because it also writes to the error stream). But in the case of mvn.bat the script is not stopped (probably because it does not write to the error stream). – Bogdan Calmac Aug 30 '11 at 16:58
  • 2
    Complete comment: I did read the response. But still,if I set $errorActionPreference to "Stop" then I would expect PS to accomodate that. In my initial post, the script stops for svn.exe (because it also writes to the error stream). But for mvn.bat the script is not stopped (because it does not write to the error stream). So, PS records the exit code of a process in $?, but it does not use it to guess whether the process failed or not. If I want to to stop the script once one of the commands fails, then I must litter my code with "if (-not $?) {exit 1}" after each command. – Bogdan Calmac Aug 30 '11 at 17:07
1

$ErrorActionPreference controls PowerShell's behavior with regard to commandlets and PowerShell functions -- it is not sensitive to exit codes of "legacy" commands. I'm still looking for a work-around for this design decision myself -- for this issue, refer to this thread: How to stop a PowerShell script on the first error?. You'll probably conclude that this custom "exec" function is the best solution: http://jameskovacs.com/2010/02/25/the-exec-problem/

With regard to the stop-on-stderr behavior, I can't reproduce this behavior in PowerShell 3:

Invoke-Command
{
  $ErrorActionPreference='Stop'
  cmd /c "echo hi >&2"          # Output to stderr (this does not cause termination)
  .\DoesNotExist.exe            # Try to run a program that doesn't exist (this throws)
  echo bye                      # This never executes
}

Update: The stop-on-stderr behavior appears to take effect when using PS remoting.

Community
  • 1
  • 1
jhclark
  • 2,493
  • 1
  • 20
  • 14