I'm having an issue with PowerShell where it will not catch an exception even when the exception is explicitly mentioned in the catch command.
In this case, I'm trying to determine if a ProcessID is still running, and if not then it will take some actions.
The sample code block that I am struggling with is:
try {
Get-Process -Id 123123 -ErrorAction 'Stop'
}
catch [Microsoft.PowerShell.Commands.ProcessCommandException] {
"Caught by Exception Type: Process is missing"
}
catch {
if ($_.Exception.getType().FullName -eq "Microsoft.PowerShell.Commands.ProcessCommandException") {
"Caught by Catch All: Process is missing"
}
}
When this code block is executed the output is:
Caught by Catch All: Process is missing
You would expect the first catch condition to trigger as it names the exception being thrown correctly, but it doesn't trigger.
To make things worse, when the second catch command runs (which catches anything) it queries the name of the exception type and checks if it is "Microsoft.PowerShell.Commands.ProcessCommandException" (which it is) and then takes appropriate steps.
I know I can work around this, but I feel I'm missing a fundamental way about how PowerShell handles Exceptions.
Can anyone shed light on this for me?
When you set ErrorAction to Stop, non-terminating errors are wrapped and thrown as type
System.Management.Automation.ActionPreferenceStopException, this is the type you want to catch.
try
{
Get-Process -Id 123123 -ErrorAction Stop
}
catch [System.Management.Automation.ActionPreferenceStopException]
{
... do something ...
}
Maybe cause you are missing an error action
try
{
kill 1234567 -ErrorAction Stop
}
catch
{
Write-Host "Blam!"
}
Related
If multiple exceptions occur in a try{} block and there is only one CATCH{} block inside the try{} block, can this CATCH{} block catch any/all the exceptions? Or do I need one CATCH{} for each possible exception?
try { CATCH { default { say "seenError" }; }; die "1"; die "2"; die "3" }
seenError
In the example above, which "die" statement was caught? 1st? If I want to handle each exception, do I need to enclose each possible exception within one separate CATCH{} ?
First of all: you do NOT need a try to have a CATCH block. In the Raku Programming Language, a CATCH block can live in any lexical scope.
So your example can become:
CATCH {
default { # $_ contains the exception
say .message; # show what the message was
}
}
die "1";
die "2";
die "3";
say "still alive";
If you run it like this, it will just say "1", implying that only the first exception was caught. And that is correct, because you do NOT change anything about the situation: the exception is still active and will cause the termination of your program.
What you need, is to resume execution after the exception was handled. And there's a method for that: .resume. It doesn't work on all exceptions, but then you will be told it doesn't work.
Changing the program to:
CATCH {
default {
say .message;
.resume; # continue execution after where exception occurred
}
}
die "1";
die "2";
die "3";
say "still alive";
This will show "1", "2", "3", "still alive".
So what does try do? Basically, it adds a CATCH block for you that will catch the first exception that it sees, put the exception in $! and return with Nil. You could think of a try block as a way to turn a fatal exception into a benign failure. You use it if you're not interested in why something failed. And try can also be a statement prefix. In short:
say try die; # Nil
(Please don't forget to accept Liz's answer. This is just an addendum to her answer.)
As Liz notes:
you do NOT need a try to have a CATCH block
And, as she implies, neither do you need a CATCH block when using try:
for 1, 2, 3 {
try { print 'something ... '; .&die } or put "seenError: $!"
}
displays:
something ... seenError: 1
something ... seenError: 2
something ... seenError: 3
As Liz also outlines, if an exception is thrown and not .resumed during processing of code that's being tryd, or if there's an unhandled Failure, the try catches the exception/failure, puts the corresponding exception in $!, and returns Nil.
I mention this to introduce one final option that might be of interest: trys, which I created for my answer to the SOQ Returning values from exception handlers.
I have following code
IAsyncOperation<bool> trythiswork()
{
bool contentFound{ false };
try
{
auto result = co_await someAsyncFunc();
winrt::check_bool(result)
if (result)
{
contentFound = true;
}
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
co_return contentFound;
}
When the result is false, it fails and throws but catch goes to fail fast and program terminates. How does log function terminate the program? Isn't it supposed to only log the exception? I assumed that I am handling this exception so program won't crash but it is crashing.
So how to throw and catch so that program does not terminate? I do want to throw. And also catch and preferably log the exception as well.
Thanks
The issue can be reproduced using the following code:
IAsyncOperation<bool> someAsyncFunc() { co_return false; }
IAsyncOperation<bool> trythiswork()
{
auto contentFound { false };
try
{
auto result = co_await someAsyncFunc();
winrt::check_bool(result);
// throw std::bad_alloc {};
contentFound = true;
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
}
co_return contentFound;
}
int main()
{
init_apartment();
auto result = trythiswork().get();
}
As it turns out, everything works as advertised, even if not as intended. When running the code with a debugger attached you will see the following debug output:
The exception %s (0x [trythiswork]
Not very helpful, but it shows that logging itself works. This is followed up by something like
FailFast(1) tid(b230) 8007023E {Application Error}
causing the process to terminate. The WIL only recognizes exceptions of type std::exception, wil::ResultException, and Platform::Exception^. When it handles an unrecognized exception type it will terminate the process by default. This can be verified by commenting out the call to check_bool and instead throwing a standard exception (such as std::bad_alloc). This produces a program that will log exception details, but continue to execute.
The behavior can be customized by registering a callback for custom exception types, giving clients control over translating between custom exception types and HRESULT values. This is useful in cases where WIL needs to interoperate with external library code that uses its own exception types.
For C++/WinRT exception types (based on hresult_error) the WIL already provides error handling helpers that can be enabled (see Integrating with C++/WinRT). To opt into this all you need to do is to #include <wil/cppwinrt.h> before any C++/WinRT headers. When using precompiled headers that's where the #include directive should go.
With that change, the program now works as desired: It logs exception information for exceptions that originate from C++/WinRT, and continues to execute after the exception has been handled.
I'm using Silex micro-framework. I searched a method to log every dbal exceptions (from requests, console commands, etc...)
I didn't find something which works. Even if I declare a callback function in $app->error();, it doesn't works to Console exceptions
How can I tell to dbal to log in a file all db errors/exceptions ?
If you have the fat version of Silex you should already have exception logging with MonologServiceProvider, as long as it has been registered.
The console is usually an instance of Symfony\Component\Console\Application (not Silex\Application).
Edit One way to accomplish logging console exceptions is to set console catch exceptions to false:
$console->setCatchExceptions(false);
And then wrap $console->run(); in a try catch:
try {
$console->run();
}
catch(\Doctrine\DBAL\DBALException $e) {
$app['monolog']->addError(sprintf('Console DBALException %s %s %s', $e->getMessage(), $e->getTraceAsString(), $e->getFile(), $e->getLine()));
}
catch(\Exception $e) {
$app['monolog']->addError(sprintf('Console Exception %s %s %s', $e->getMessage(), $e->getTraceAsString(), $e->getFile(), $e->getLine()));
}
I am trying my first features with Behat and I am facing the problem I don't know how to implement expected exceptions.
I found the issue https://github.com/Behat/Behat/issues/140 and robocoder is talking about one possible way, which is used by Behat, too. But it seems that they aren't really handling exceptions.
My point is to achieve forced exception handling. I don't want any construct catching all exceptions and forget them.
One possible way would be:
When <player> transfers <transfer> from his account it should fail with <error>
Implementation
try {
...
} catch (\Exception $ex) {
assertEquals($error, $ex->getMessage());
}
I don't like the scenario description. I want to use the then keyword, e.g.
When <player> transfers <transfer> from his account
Then it should fail with error <error>
This description has the disadvantage I need two methods:
method1($arg1, $arg2) {
// Test the transfer
}
method2($arg1, $arg2) {
// Check if the exception is the right one
}
To be able to check in method2 the exception needs to be stored.
The only possible way I see is to use a try/catch and store it to a variable.
Someone else would catch it and do nothing with it. Nobody will notice, when running the tests.
How can I prevent that exceptions are discarded?
Has anybody else a similar scenario implemented?
Thanks for any hints.
EDIT:
Behat context:
playerTransfer($player, $amount) {
$player->transfer($amount);
}
Method from entity class:
transfer($amount) {
if ($this->getWealth() < $amount) {
throw NotEnoughMoney();
}
...
}
Always try to catch method outcome to context class field, for example:
//inside Behat context class method
try {
$this->outcome = $func();
}
catch(\Exception $ex) {
$this->outcome = $ex;
}
Now when expecting exception at next step just check if $this->outcome is instanceof desired exception with message/code.
I think the problem is in your implementation. Do you check if transfer is successful in "When transfers from his account" ? Do you need to check it ?
Failure test:
When <player> transfers <transfer> from his account
Then I should see error <error>
Successful step:
When <player> transfers <transfer> from his account
Then I should see "transfer successful"
Here's how I successfully did it in a project of mine where I had to repeat a few steps till the condition held true:
/**
* #Given /^I execute some conditions$/
*/
public function executeConditions()
{
$flag = 1;
do {
try {
<steps to be executed till the condition holds true>
$flag=1;
} catch (\Exception $ex) {
$flag = 0;
}
}while ($flag>0);
}
I have a two Powershell scripts; main.ps1 and sub.ps1. main.ps1 calls sub.ps1. Sometimes sub.ps1 throws an exception. Is it possible to catch the exception thrown by sub.ps1 from main.ps1 ?
Example main.ps1:
try{. .\sub.ps1;}
catch
{}
finally
{}
Example sub.ps1:
throw new-object System.ApplicationException "I am an exception";
Here is a simple example:
try {
sub.ps1
}
catch {
Write-Warning "Caught: $_"
}
finally {
Write-Host "Done"
}
Use help about_Try_Catch_Finally for more details.
Yet another way is to use trap, see help about_trap. If you have some C# or C++ background then I would recommend to use Try_Catch_Finally approach (but it also depends on what exactly you do).