PowerShell and exit code 0

Published on: 2 Apr 2013

Octopus Deploy has had two different ways to execute PowerShell scripts. Initially we hosted PowerShell inside an AppDomain, and invoked a pipeline. That approach had problems, so now we simply call PowerShell.exe over the script and pipe the results.

One problem I hit when I changed our approach is the way PowerShell uses return codes. I assumed (wrongly) that if a script ran successfully, 0 would be returned, and if it failed (an exception, invalid syntax, etc.) the code would be non-zero.

So here's a test - create this file in PowerShell:

# Call a command that doesn't exist

Now run it, and print the return code it returns:

Exits with code 0

Now try this script:

# Parser error

Exits with code 0


# Invalid argument
New-Item -Dwarf Sneezy

Exits with code 0

Obviously, exit code 0 in PowerShell can signify anything from "the script ran perfectly" to "your script is so utterly broken that PowerShell will be uninstalled". One might argue that this is the correct behavior, because PowerShell did its job successfully (running a script) but that the script was incorrect, and that's not PowerShell's fault. Personally, I disagree with that approach. It would be like the C# compiler returning exit code 0 for code that doesn't compile, because it's not the compilers fault that the code is bad.

So, I couldn't rely on exit codes alone to tell Octopus that a script failed.

However, all of these kinds of errors do write to the stderr stream, which is good. So I figured, if the script is writing to stderr, there's some kind of problem with the script, and we can use a write to stderr as a signal to fail the script. That's what I did in Octopus 1.4.

But this didn't work so well in practice - it turns out people use stderr a lot for things that they don't want to fail the deployment. So I got a lot of bug reports about scripts that ran "OK" but were being treated as fails.

So now, I don't do anything with the return code (oh, except I do set the PowerShell exit code if $LastExitCode is non-zero). It's up to you to check for errors and return an appropriate exit code when your script runs. PowerShell makes it really easy to do that.

Writes to stderr will result in a warning in your deployment log, however. And you can use the special Octopus variable OctopusTreatWarningsAsErrors to have Octopus fail the deployment if there's a warning. So this is a way you can have Octopus fail when stderr is written even if PowerShell exited with code 0.