Powershell 在函数中捕获异常 8


决定异常产生后脚本是继续执行还是停止执行与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/ &lt;&lt;&lt;&lt; $null
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

Trap 到异常了.
Get-Process : 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。
所在位置 E:MyScript.ps1:6 字符: 12
+ Get-Process &lt;&lt;&lt;&lt; "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 &lt;&lt;&lt;&lt; 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: 试图除以零。
本文链接: http://www.pstips.net/powershell-trap-error-in-function.html
请尊重原作者和编辑的辛勤劳动,欢迎转载,并注明出处!

关于 Mooser Lee

我是一个Powershell的爱好者,创建了PowerShell中文博客,热衷于Powershell技术的搜集和分享。本站部分内容来源于互联网,不足之处敬请谅解,并欢迎您批评指正。


发表评论

电子邮件地址不会被公开。 必填项已用*标注

8 条评论 “Powershell 在函数中捕获异常

    • 荔非苔 文章作者

      描述复杂,估计我我翻译水平有限,翻译的太绕口。我个人还是蛮喜欢这样的设计:先是命令层面:ErrorAction 。 局部控制出错后的动作。然后是全局:$ErrorActionPreference。全局控制出错后的动作。中间还有脚本块层面:Trap。Trap可以简化Try-Catch-Finally逻辑。最后:同时兼容Try-Catch-Finally主要初衷:Powershell的核心功能是管理和配置,一般都是成批处理,这一批命令可以全部完成,也可以部分完成,也可以部分出错。另外有的命令,本身就要依赖错误,比如ls,访问无权限目录会出错,可能恰好是用户需要的,可以用命令本身的ErrorAction。 个人愚见。

  • elale

    Function Test-Func
    {
    Trap { “Trap 到异常了.” }
    1/$null
    Get-Process “NoSuchProcess”
    Dir MossFly:
    }
    Test-Func

    这里面的确只trap到一个异常,即除零异常,但原因不是文中所说,而是只有1/$null能被trap到,其他两个都无法被trap语句抓住。
    我试过把1/$null放在最后也是一样的结果。

  • elale

    只要把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