Как предотвратить внешний script от завершения вашего script с помощью оператора break

Я вызываю внешний файл .ps1, содержащий инструкцию break в определенных условиях ошибки. Я хотел бы как-то поймать этот сценарий, разрешить любые сообщения, напечатанные извне, как обычно, и продолжить с последующими утверждениями в моем script. Если внешний script имеет throw, это работает отлично, используя try/catch. Даже с trap в моем файле я не могу остановить завершение script.

Чтобы ответить на этот вопрос, предположим, что исходный код внешнего файла .ps1 (созданный кем-то другим и втянутый во время выполнения) не может быть изменен.

Является ли то, что я хочу, или автор script просто не думал о том, чтобы играть красиво, когда вызывается извне?

Изменить: укажите следующий пример.

В файле badscript.ps1:

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

В myscript.ps1:

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

Результаты, которые я хотел бы получить, - это увидеть предупреждение от badscript.ps1 и продолжить его с дальнейшими операциями в myscript.ps1. Я понимаю, почему выражение о разрыве причины "Это сегодня". чтобы никогда не печататься, однако я хотел найти способ обойти его, поскольку я не являюсь автором badscript.ps1.

Изменить: Обновление заголовка из "powershell try/catch не ломает оператор break" на "как предотвратить внешний script от завершения вашего script с помощью оператора break". Упоминание try/catch было действительно больше об одном неудавшемся решении фактического вопроса, который лучше отражает новый заголовок.

Ответ 1

Я получаю, откуда вы. Вероятно, самым простым способом было бы отключить script как задание и дождаться результатов. Вы даже можете повторить результаты с помощью Receive-Job после этого, если хотите.

Итак, учитывая плохой script, который у вас выше, и этот script файл вызывает его:

$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"

Это приведет к неудачному script в задании, дождитесь результатов, повторит результаты и продолжит выполнение script.

Это может быть завернуто в функцию для любых скриптов, которые вам могут потребоваться (просто чтобы быть в безопасности).

Здесь вывод:

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

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

Ответ 2

Запуск отдельного процесса PowerShell из моего script для вызова внешнего файла оказался подходящим решением для моих нужд: powershell -File .\badscript.ps1 будет выполнять содержимое файла badscript.ps1 до тех пор, пока инструкция break, включая любой Write-Host или Write-Warning, и пусть мой собственный script продолжит.

Ответ 3

В документации about_Break говорится

PowerShell не ограничивает, насколько далеко метки могут возобновить выполнение. метка может даже передавать управление через скрипт и вызов функции границы.

Это заставило меня задуматься: "Как я могу обмануть этот глупый выбор языка?". И ответ заключается в создании небольшого блока switch, который будет удерживать break при выходе:

.\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"

Затем, когда мы вызываем OuterScript.ps1, мы получаем

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

Обратите внимание, что OuterScript.ps1 правильно возобновил работу после вызова NaughtyBreak.ps1, встроенного в коммутатор, но был убит бесцеремонно при непосредственном вызове NaughtyBreak.ps1.

Ответ 4

Положить разрыв обратно в цикл (включая переключатель), где он принадлежит.

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