4

I am calling an external .ps1 file which contains a break statement in certain error conditions. I would like to somehow catch this scenario, allow any externally printed messages to show as normal, and continue on with subsequent statements in my script. If the external script has a throw, this works fine using try/catch. Even with trap in my file, I cannot stop my script from terminating.

For answering this question, assume that the source code of the external .ps1 file (authored by someone else and pulled in at run time) cannot be changed.

Is what I want possible, or was the author of the script just not thinking about playing nice when called externally?

Edit: providing the following example.

In badscript.ps1:

if((Get-Date).DayOfWeek -ne "Yesterday"){
    Write-Warning "Sorry, you can only run this script yesterday."
    break
}

In myscript.ps1:

.\badscript.ps1
Write-Host "It is today."

The results I would like to achieve is to see the warning from badscript.ps1 and for it to continue on with my further statements in myscript.ps1. I understand why the break statement causes "It is today." to never be printed, however I wanted to find a way around it, as I am not the author of badscript.ps1.

Edit: Updating title from "powershell try/catch does not catch a break statement" to "how to prevent external script from terminating your script with break statement". The mention of try/catch was really more about one failed solution to the actual question which the new title better reflects.

7
  • 3
    break won't trigger an error, no. If the break statement is only invoked conditioned on errors being thrown otherwise in the script, you could set $ErrorActionPreference = 'Stop' Commented Aug 18, 2017 at 0:09
  • 1
    try and catch are for exceptions, as is throw. break has nothing to do with it. Your question doesn't make sense/ Commented Aug 18, 2017 at 0:12
  • @EJP the whole point of this question is whether there is a mechanism by which I could get similar results for catching an exception. Makes perfect sense to me: how can you get an external script call to not stop your script's execution? Commented Aug 18, 2017 at 1:01
  • @MathiasR.Jessen Unfortunately some of the break statements are used after non-erroring conditional statements, so perhaps I wasn't precise enough in calling them "error conditions". Also, I wouldn't want to globally force all the other scripts non-terminating errors to become terminating errors, as it handles some of the gracefully. Commented Aug 18, 2017 at 1:06
  • 1
    This question might make more sense if you included some examples of what you have now so we can see the issue you are trying to fix. The question seems unclear and the comments are attempting to clarify this. see minimal reproducible example Commented Aug 18, 2017 at 1:31

4 Answers 4

2

Running a separate PowerShell process from within my script to invoke the external file has ended up being a solution good enough for my needs: powershell -File .\badscript.ps1 will execute the contents of badscript.ps1 up until the break statement including any Write-Host or Write-Warning's and let my own script continue afterwards.

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

Comments

1

I get where you're coming from. Probably the easiest way would be to push the script off as a job, and wait for the results. You can even echo the results out with Receive-Job after it's done if you want.

So considering the bad script you have above, and this script file calling it:

$path = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent

$start = Start-Job -ScriptBlock { . "$using:Path\badScript.ps1" } -Name "BadScript"

$wait = Wait-Job -Name "BadScript" -Timeout 100
Receive-Job -Name "BadScript"
Get-Command -Name "Get-ChildItem"

This will execute the bad script in a job, wait for the results, echo the results, and then continue executing the script it's in.

This could be wrapped in a function for any scripts you might need to call (just to be on the safe side.

Here's the output:

WARNING: Sorry, you can only run this script yesterday.

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Get-ChildItem                                      3.1.0.0    Microsoft.PowerShell.Management

1 Comment

While Start-Job | Wait-Job is a little more complicated compared to my answer for something that needs to be synchronous, I really appreciate this one which stays wholly in commandlets!
1

In the about_Break documentation it says

PowerShell does not limit how far labels can resume execution. The label can even pass control across script and function call boundaries.

This got me thinking, "How can I trick this stupid language design choice?". And the answer is to create a little switch block that will trap the break on the way out:

.\NaughtyBreak.ps1

Write-Host "NaughtyBreak about to break"
break

.\OuterScript.ps1

switch ('dummy') { default {.\NaughtyBreak.ps1}}

Write-Host "After switch() {NaughtyBreak}"

.\NaughtyBreak.ps1

Write-Host "After plain NaughtyBreak"

Then when we call OuterScript.ps1 we get

NaughtyBreak about to break
After switch() {NaughtyBreak}
NaughtyBreak about to break

Notice that OuterScript.ps1 correctly resumed after the call to NaughtyBreak.ps1 embedded in the switch, but was unceremoniously killed when calling NaughtyBreak.ps1 directly.

2 Comments

If NaughtyBreak.ps1 has break non_existing_label, it will terminate the caller script. (Obviously this would only happen if the NaughtyBreak author intends it.)
@Silvar Good catch. That seems like a security issue. Imagine NaughtyBreak.ps1 knows the caller script has a particular enclosing label. It can then break execution to that label and there is nothing the outer script can do to stop it. Seems very wrong.
1

Putting break back inside a loop (including switch) where it belongs.

foreach($i in 1) { ./badscript.ps1 } 
'done'

Or

switch(1) {  1 { ./badscript.ps1 } }
'done'

3 Comments

Haha, clever. From experiences in other languages I never would have expected a break statement could affect a flow structure in a different file/function :)
I didn't know it either until your question. I know scripts you call can inherit the first script's variables. But they each have their own scope.
BTW, this won't work if the badscript author is 'clever' and actively trying to make the caller script to terminate: If they qualify break with a non-existing label, the caller script will always terminate. Of course the author of the caller script can examine badscript and make sure the call to it is enclosed with the needed labeled loops/switches to circumvent this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.