Reputation: 2703
When executing such a script:
nonexistingcommand
echo "Hello"
I get:
nonexistingcommand : The term 'nonexistingcommand' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the
name, or if a path was included, verify that the path is correct and try again.
At D:\Playground\powershell\Test.ps1:2 char:1
+ nonexistingcommand
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (nonexistingcommand:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Hello
So it seems that the CommandNotFoundException
is a non-terminating error. So why if I
try {
nonexistingcommand
}
catch [System.Management.Automation.CommandNotFoundException] {
throw
}
echo "Hello"
In this case, it will exit and not print "Hello".
Why is that?
Upvotes: 2
Views: 1989
Reputation: 438208
Unfortunately, PowerShell has two types of terminating errors:
Statement-terminating errors, which by default only terminate the enclosing statement.
By default, execution resumes, namely with the next statement (echo "Hello"
in your case)
CommandNotFoundException
is an instance of such an error.
By contrast, non-terminating errors continue processing even of the originating statement, if further pipeline input is available (e.g., Get-ChildItem NoSuchDir, \
emits a non-terminating error for non-existing dir. NoSuchDir
, then goes on to successfully report on existing dir. \
)
Script-terminating (thread-terminating) errors, which terminate the enclosing script and the entire call stack.
throw
statement called from PowerShell code, never by binary (compiled) cmdlets.The try { ... } catch { ... } finally { ... }
statement does not distinguish between these two subtypes: it catches them both.
catch
block contains an argument-less throw
statement, which implicitly relays the error that triggering error, you're effectively turning the statement-terminating error into a script-terminating one, so execution ends there.Similarly, setting the $ErrorActionPreference
preference variable to 'Stop'
causes all types of errors (emitted by PowerShell commands[1]), including non-terminating ones, to abort execution overall; in other words: both non-terminating and statement-terminating errors are promoted to script-terminating ones.
For a comprehensive overview of PowerShell's surprisingly complex error handling, see GitHub docs issue #1583.
[1] At least in local, foreground invocations of external programs in consoles (terminals), stderr output is by default not routed via PowerShell's error stream, and therefore not affected by $ErrorActionPreference
.
However, in PowerShell v7.1 and below, including in Windows PowerShell, using a 2>
redirection does route stderr through PowerShell's error stream, which can have unexpected side effect. This problem will be fixed in v7.2.
Note that the behavior is PowerShell host-specific and applies to host ConsoleHost
(use $host
to get host information). Other hosts still invariably route stderr via the error stream, which notably affects remoting and background jobs.
Upvotes: 5
Reputation: 572
The above error that states command was not found is a terminating error. When such an error is encountered, powershell pipeline stops execution. Only the statements within catch block are executed.
To know the difference between terminating and non-terminating errors, checkout this link: https://www.tutorialspoint.com/what-is-terminating-and-non-terminating-errors-in-powershell
If some statements are to be executed even if you encounter a terminating error, specify them within finally:
try {
nonexistingcommand
}
catch [System.Management.Automation.CommandNotFoundException] {
throw
}
finally {
echo "Hello"
}
The above will print Hello
Upvotes: 0