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 rubbish
Now, run it and print the return code it returns:
Now, try this script:
# Parser error !
# Invalid argument New-Item -Dwarf Sneezy
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.
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.
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.