关于Powershell:如何防止外部脚本使用break语句终止脚本

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

我正在调用外部.ps1文件,该文件在某些??错误情况下包含break语句。我想以某种方式捕获这种情况,允许所有外部打印的消息正常显示,并继续执行脚本中的后续语句。如果外部脚本具有throw,则使用try / catch可以正常工作。即使文件中包含trap,也无法停止脚本终止。

为了回答这个问题,假设不能更改外部.ps1文件的源代码(由他人创作并在运行时插入)。

我想要的是可能的吗,还是脚本的编写者只是在外部调用时不考虑打得好?

编辑:提供以下示例。

在badscript.ps1中:

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

在myscript.ps1中:

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

我想获得的结果是看到badscript.ps1发出的警告,并继续在myscript.ps1中继续我的声明。我理解break语句为何导致"今天"。永远不会被打印,但是我想找到一种解决方法,因为我不是badscript.ps1的作者。

编辑:将标题从" powershell tr??y / catch不能捕获break语句"更新为"如何防止外部脚本使用break语句终止脚本"。提到try / catch的确是解决实际问题的一个失败解决方案,新标题可以更好地反映这一问题。


从脚本内部运行单独的PowerShell进程以调用外部文件,最终成为了一种足以满足我需要的解决方案:
powershell -File .\badscript.ps1将一直执行badscript.ps1的内容,直到break语句(包括任何Write-Host或Write-Warning语句)为止,然后让我自己的脚本继续。


我知道你来自哪里。可能最简单的方法是将脚本作为工作推送,然后等待结果。如果需要,您甚至可以在完成后用Receive-Job回显结果。

因此,考虑到上面有错误的脚本,以及此脚本文件将其调用:

1
2
3
4
5
6
7
$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"

这将在作业中执行错误的脚本,等待结果,回显结果,然后继续执行其中的脚本。

这可以包装在您可能需要调用的所有脚本的函数中(出于安全考虑。

这是输出:

1
2
3
4
5
WARNING: Sorry, you can only run this script yesterday.

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


将中断放回其所属的循环(包括开关)中。

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


在about_Break文档中说

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

这让我开始思考:"我该如何欺骗这种愚蠢的语言设计选择?"。答案是创建一个小的switch块,该块会在出路时捕获break

。 naughtyBreak.ps1

1
2
Write-Host"NaughtyBreak about to break"
break

。 OuterScript.ps1

1
2
3
4
5
6
7
8
9
switch ('dummy') { default {.
aughtyBreak.ps1}}

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

.
aughtyBreak.ps1

Write-Host"After plain NaughtyBreak"

然后,当我们调用OuterScript.ps1时,我们得到

1
2
3
NaughtyBreak about to break
After switch() {NaughtyBreak}
NaughtyBreak about to break

请注意,在对嵌入在交换机中的NaughtyBreak.ps1的调用之后,OuterScript.ps1可以正确恢复,但是在直接调用NaughtyBreak.ps1时被毫不客气地杀死了。