DannyMeister
DannyMeister

Reputation: 1303

how to prevent external script from terminating your script with break statement

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.

Upvotes: 4

Views: 1121

Answers (4)

js2010
js2010

Reputation: 27491

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'

Upvotes: 1

John Rees
John Rees

Reputation: 1813

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.

Upvotes: 1

DannyMeister
DannyMeister

Reputation: 1303

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.

Upvotes: 2

SamuelWarren
SamuelWarren

Reputation: 1459

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

Upvotes: 1

Related Questions