How to catch an exception thrown in another Powershell script? - exception

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).

Related

How many exceptions does one CATCH block catch?

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.

haxe macro catching of Context.parse() errors

At compile (macro) time, calling
Context.parse("a bad expression", somePos)
produces an error that cannot be caught in a try-catch block (Edit: this is wrong, see below). Is there a way to catch this error? Context.parseInlineString() doesn't seem to work either.
Others functions such as Context.typeExpr() have a similar problem.
Edit:
The type of catch was wrong. I did:
try {...}
catch (err:String) {...}
What you have to do:
try {...}
catch (err:Dynamic) {...}
Careful reading of the documentation explains this. This is different than Java for which there is one type of exception per error. In Haxe, most errors are strings, but there are some others like the one here.
The following works for me:
import haxe.macro.*;
class Test {
macro static function test() {
try {
Context.parse("a bad expression", Context.currentPos());
} catch(e:Dynamic) {
trace(e); //Test.hx:8: Missing ;
}
return macro {};
}
static function main() {
test();
}
}

How to implement expected exceptions?

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);
}

PowerShell catching typed exceptions

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!"
}

Avoid throwing a new exception

I have an if condition which checks for value and the it throws new NumberFormatException
Is there any other way to code this
if (foo)
{
throw new NumberFormatException
}
// ..
catch (NumberFormatException exc)
{
// some msg...
}
If you are doing something such as this:
try
{
// some stuff
if (foo)
{
throw new NumberFormatException();
}
}
catch (NumberFormatException exc)
{
do something;
}
Then sure, you could avoid the exception completely and do the 'do something' part inside the conditional block.
If your aim is to avoid to throw a new exception:
if(foo)
{
//some msg...
} else
{
//do something else
}
Don't throw exceptions if you can handle them in another, more elegant manner. Exceptions are expensive and should only be used for cases where there is something going on beyond your control (e.g. a database server is not responding).
If you are trying to ensure that a value is set, and formatted correctly, you should try to handle failure of these conditions in a more graceful manner. For example...
if(myObject.value != null && Checkformat(myObject.Value)
{
// good to go
}
else
{
// not a good place to be. Prompt the user rather than raise an exception?
}
In Java, you can try parsing a string with regular expressions before trying to convert it to a number.
If you're trying to catch your own exception (why???) you could do this:
try { if (foo) throw new NumberFormatException(); }
catch(NumberFormatexception) {/* ... */}
if you are trying to replace the throwing of an exception with some other error handling mechanism your only option is to return or set an error code - the problem is that you then have to go and ensure it is checked elsewhere.
the exception is best.
If you know the flow that will cause you to throw a NumberFormatException, code to handle that case. You shouldn't use Exception hierarchies as a program flow mechanism.