决定异常产生后脚本是继续执行还是停止执行与ErrorAction和Traps有关。因为Traps运行在ErrorAction之后,即使ErrorAction的参数为Stop,也有可能被Trap的设置覆盖。
因为系统中$ErrorActionPreference的默认值为Continue,下面函数中的脚本遇到错误时,会继续执行。但是Trap只会执行一次。
Function Test-Func { Trap { "Trap 到异常了." } 1/$null Get-Process "NoSuchProcess" Dir MossFly: } Test-Func E:MyScript.ps1 Trap 到异常了. 试图除以零。 所在位置 E:MyScript.ps1:4 字符: 3 + 1/ <<<< $null + CategoryInfo : NotSpecified: (:) [], RuntimeException + FullyQualifiedErrorId : RuntimeException Get-Process : 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。 所在位置 E:MyScript.ps1:5 字符: 12 + Get-Process <<<< "NoSuchProcess" + CategoryInfo : ObjectNotFound: (NoSuchProcess:String) [Get-Proc ess], ProcessCommandException + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell. Commands.GetProcessCommand Get-ChildItem : 找不到驱动器。名为“MossFly”的驱动器不存在。 所在位置 E:MyScript.ps1:6 字符: 4 + Dir <<<< MossFly: + CategoryInfo : ObjectNotFound: (MossFly:String) [Get-ChildItem] , DriveNotFoundException + FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetC hildItemCommand
因为如果ErrorAction没有设置为Stop,ErrorAction不会向被调用者报告每个异常。一旦将ErrorAction设置为Stop,则会每次报告异常,每次都会被Trap到。
Function Test-Func { Trap { "Trap 到异常了." } 1/$null Get-Process "NoSuchProcess" -ErrorAction Stop Dir MossFly: -ErrorAction Stop } Test-Func Trap 到异常了. 试图除以零。 所在位置 E:MyScript.ps1:5 字符: 3 + 1/ <<<< $null + CategoryInfo : NotSpecified: (:) [], RuntimeException + FullyQualifiedErrorId : RuntimeException Trap 到异常了. Get-Process : 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。 所在位置 E:MyScript.ps1:6 字符: 12 + Get-Process <<<< "NoSuchProcess" -ErrorAction Stop + CategoryInfo : ObjectNotFound: (NoSuchProcess:String) [Get-Proc ess], ProcessCommandException + FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell. Commands.GetProcessCommand Trap 到异常了. Get-ChildItem : 找不到驱动器。名为“MossFly”的驱动器不存在。 所在位置 E:MyScript.ps1:7 字符: 4 + Dir <<<< MossFly: -ErrorAction Stop + CategoryInfo : ObjectNotFound: (MossFly:String) [Get-ChildItem] , DriveNotFoundException + FullyQualifiedErrorId : DriveNotFound,Microsoft.PowerShell.Commands.GetC hildItemCommand [ps/] 如果在Trap中使用了Continue,可以屏蔽默认的异常输出,也可以定制自己的异常。 <pre class="brush:powershell"> Function Test-Func { Trap { "Trap到了异常: $($_.Exception.Message)"; Continue } 1/$null Get-Process "NoSuchProcess" -ErrorAction Stop Dir MossFly: -ErrorAction Stop } Test-Func Trap到了异常: 试图除以零。 Trap到了异常: 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。 Trap到了异常: 找不到驱动器。名为“MossFly”的驱动器不存在。
如果你想让脚本在第一次遇到异常就停止工作,可以在Trap中添加Break,如下:
Function Test-Func { Trap { "Trap到了异常: $($_.Exception.Message)"; Break } 1/$null Get-Process "NoSuchProcess" -ErrorAction Stop Dir MossFly: -ErrorAction Stop } Test-Func Trap到了异常: 试图除以零。 试图除以零。 所在位置 E:MyScript.ps1:8 字符: 3 + 1/ <<<< $null + CategoryInfo : NotSpecified: (:) [], ParentContainsErrorRecordExc eption + FullyQualifiedErrorId : RuntimeException
如果将Trap放在函数的调用者中,并跟上Continue,这样函数中第一条错误发生,脚本就会终止执行,并且屏蔽Powershell默认的错误输出。
function Caller { Trap { "Trap Error: $($_.Exception.Message)"; Continue } Test-Func } function Test-Func { 1/$null Get-Process "nosuchthing" -ea Stop Dir xyz: -ea Stop } Caller #Trap Error: 试图除以零。
在Powershell中还可以嵌套函数,也就是函数中定义函数。Trap 定义在外部函数,内部函数的异常,会在外部被捕获。此时的内部函数就像一连串的脚本块。
function test-func { # 将 Trap 定义在函数外面: Trap {"Trap Error: $($_.Exception.Message)"; Continue} # 内部函数 function InnerCore { 1/$null Get-Process "nosuchthing" -ea Stop Dir xyz: -ea Stop } InnerCore } test-func #Trap Error: 试图除以零。
其实也没有必要定义内部函数,因为脚本块也可以做到这一点。可以通过&符号定义脚本块。
function test-func { # 将 Trap 定义在函数外面: Trap {"Trap Error: $($_.Exception.Message)"; Continue} # 内部函数 &{ 1/$null Get-Process "nosuchthing" -ea Stop Dir xyz: -ea Stop } } test-func #Trap Error: 试图除以零。
本文链接: https://www.pstips.net/powershell-trap-error-in-function.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!
为什么描述会这么复杂?这样设计是什么理念?
描述复杂,估计我我翻译水平有限,翻译的太绕口。我个人还是蛮喜欢这样的设计:先是命令层面:ErrorAction 。 局部控制出错后的动作。然后是全局:$ErrorActionPreference。全局控制出错后的动作。中间还有脚本块层面:Trap。Trap可以简化Try-Catch-Finally逻辑。最后:同时兼容Try-Catch-Finally主要初衷:Powershell的核心功能是管理和配置,一般都是成批处理,这一批命令可以全部完成,也可以部分完成,也可以部分出错。另外有的命令,本身就要依赖错误,比如ls,访问无权限目录会出错,可能恰好是用户需要的,可以用命令本身的ErrorAction。 个人愚见。
Function Test-Func
{
Trap { “Trap 到异常了.” }
1/$null
Get-Process “NoSuchProcess”
Dir MossFly:
}
Test-Func
这里面的确只trap到一个异常,即除零异常,但原因不是文中所说,而是只有1/$null能被trap到,其他两个都无法被trap语句抓住。
我试过把1/$null放在最后也是一样的结果。
只要把trap放到函数体外而不用专门的caller函数一样可以实现文中的效果。下例中第一个异常被trap到就停止了。如果把trap函数放到函数体内和异常在一级,3个异常都会被trap到
trap
{
write-host “exceptions trapped! msg is: $($_.exception.message)”
$_.exception.gettype().fullname
continue
}
function Test-Func{
$ErrorActionPreference = “Stop”
Get-Process “NoSuchProcess”
Dir MossFly:
1/$null
}
Test-Func
搜了下,发现PS也有try/catch/finally,可参考“wragg.io/powershell-try-catch”。
并不是所有的异常try-catch都能捕获,这里区分终止异常和非终止异常。
嗯, 可以用-ErrorAction 设置是不是终止异常,然后就可以捕获了。主要是try/catch更符合编程习惯