0

I’ve got a simple powershell script like this:

Set-Strictmode -version Latest
$ErrorActionPreference = 'Stop'

try
{
  Write-Host "aaa $(MyFunc "bbb)"
}
catch
{
  Write-Host "Caught the error!"
  Write-Host $error
  exit 666
}

(Note that this script has an error in the first Write-Host line.)

I need my scripts to run in such a way that if there are any errors, it will return with a non-zero value. This is the purpose of setting “Set-Strictmode”, “$ErrorActionPreference”, and wrapping it all in a try…catch block.

But when I run it from the windows cmd.exe, you can see that the error is not caught and that it does not return an error code:

D:\jjj>powershell -F jjj.ps1
At D:\jjj\jjj.ps1:6 char:28
+   Write-Host "aaa $(MyFunc "bbb)"
+                            ~~~~~
The string is missing the terminator: ".
At D:\jjj\jjj.ps1:6 char:34
+   Write-Host "aaa $(MyFunc "bbb)"
+                                  ~
Missing closing ')' in subexpression.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString

D:\jjj>echo Exit Code is %errorlevel%
Exit Code is 0

I suspect that the unmatched quotes in the errorful line is mangling the interpretation so much that the try…catch block is never properly instantiated.

So, here’s the question: what can I do to ensure that any execution errors of my PowerShell script cause it to return with a non-zero errorcode?

1 Answer 1

4

You have a syntax error there, not a runtime error. There's nothing you can do except actually fixing it. Syntax errors can't be caught at runtime, because they occur when PowerShell parses the code, i.e. before the instructions actually get executed.

If you run the script from within PowerShell the automatic variable $? will be set to $false, though. If you run it in a new powershell process like this:

powershell "C:\path\to\your.ps1"

the errorlevel ($LASTEXITCODE in PowerShell) will be set to 1 on errors. Unfortunately the errorlevel is not set when you run the script using the -File parameter:

powershell -File "C:\path\to\your.ps1"

which you'd normally do to have regular exit codes from the script returned to the caller.

Sign up to request clarification or add additional context in comments.

5 Comments

Is there no way to get PowerShell to return an error if it encounters an error while parsing?
@Portman You have to do that from separate parse context. Something like: PowerShell -Command "try{.\SomeOtherFile.ps1}catch{exit 666}".
And this is a problem. I have a script that requires a certain version of Powershell and with a lower version it silently fails with a parse error. I have a check to require a particular Powershell version and exit with an error result if the requirement is not met, but it never gets executed because of a parse error.
By the way #Requires directives are completely useless for this purpose, because they also cause the parser to silently fail. And if I wrap the script using -Command, I mask the exit code of the script itself.
To actually catch the parse errors (so that I can catch the condition that the script is being run in wrong Powershell version where a particular construct is unsupported, or failing #Requires directives), and pass the exit code of the called script, use the following command: PowerShell -ExecutionPolicy Unrestricted -Command "try { .\MyScript.ps1 } catch { Write-Error $_; exit 255 } exit $LASTEXITCODE"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.