11

我试图让我的脚本在遇到错误时停止,并使用 try...catch 给我一个简单的方法来处理错误。世界上最简单的事情我会想到,但我显然在做一些愚蠢的事情。我已经阅读了几个小时,但我被卡住了,任何帮助都会非常方便,谢谢!

这是一些示例代码,我已经把错误操作放在了所有地方,似乎无法阻止这该死的东西!

$ErrorActionPreference = "Stop"
try {
    get-content "c:\GarbageFileName.txt" -ErrorAction stop
}
catch {
    write-output "in catch, I want it to stop now"
}
write-output "try-catch finished, script is continuing"

第二天添加的此文本* 来自人们的精彩回答,我希望我可以选择超过 1 个答案或有足够的声誉来投票给那些我不情愿地没有选择作为答案的答案,或者以某种方式表示感谢!

4

3 回答 3

18

try/catch控件的整个想法是告诉脚本如果遇到终止错误该怎么做,而不是抛出错误并停止脚本的默认操作。如果您的 catch 块仅使用Write-Host向终端显示一条消息,那么这就是所有的错误处理,并且脚本将从那里继续。如果您考虑一下,如果在捕获到错误时自动停止脚本,它将部分破坏try/catch的目的。

catch块中,$_将设置为 ErrorRecord 对象,表示来自try块的终止错误(与存储在$error[0]中的相同)。所以结束脚本最简单的方法是重新抛出如果你没有使用try/catch会抛出的错误:

try {
  Get-Content "c:\GarbageFileName.txt" -ErrorAction stop
} catch {
  # Custom action to perform before terminating
  throw $_
}

或者,如果您想显示自定义消息而不是默认的 ErrorRecord:

try {
  Get-Content "c:\GarbageFileName.txt" -ErrorAction stop
} catch {
  throw 'Custom error message'
}

或者,如果您想在完成自定义错误处理后退出而不向错误流抛出错误,则可以按照 Joost 的回答中的建议使用break 。

或者您可以变得更复杂并创建自己的 ErrorRecord 对象。你可以做很多事情,这个话题太大了,无法在这里全面介绍,但你可以通过谷歌搜索System.Management.Automation.ErrorRecord获得有关语法的更多信息。这是我的一个脚本中的一个示例,可帮助您入门(来自一个针对 SQL Server 数据库执行$query变量中定义的 SQL 查询的函数):

} catch {
  $ErrorRecord = New-Object System.Management.Automation.ErrorRecord(
    (New-Object Exception("Exception executing the query: $($_.Exception.InnerException.Message)")),
    $query,
    [System.Management.Automation.ErrorCategory]::InvalidArgument,
    $null
  )
  $ErrorRecord.CategoryInfo.Reason = $_.CategoryInfo.Reason;
  $ErrorRecord.CategoryInfo.Activity = $_.InvocationInfo.InvocationName;
  $PSCmdlet.ThrowTerminatingError($ErrorRecord);
}

几点注意事项:

  • 您会看到,在创建我的自定义 ErrorRecord 时,我使用了 $_ ,我刚才说过它包含与try块中捕获的终止错误关联的 ErrorRecord 对象。这个想法是自定义一些错误输出,同时通过将默认 ErrorRecord 的部分分配给自定义 ErrorRecord 的相应属性来使用它们。
  • $PSCmdlet仅在您[CmdletBinding()]在函数或脚本的开头声明时可用。否则,您可以使用throw $ErrorRecord抛出您的自定义错误。但是,如果您使用$PSCmdlet.ThrowTerminatingError,结果将更像 Cmdlet 样式。(throw将从产生错误的函数中吐出该行,而$PSCmdlet.ThrowTerminatingError将为您提供使用该函数的调用上下文中的行。很难以一种有意义的方式来描述而不会过于详细,但如果你尝试一下,你就会明白我的意思。)

顺便说一句,设置$ErrorActionPreference = "Stop",然后使用是多余的-ErrorAction Stop。首选项变量设置所有 cmdlet 的默认操作,并且-ErrorAction开关覆盖特定 cmdlet 的默认操作,因此无需先指定默认值,然后使用-ErrorAction指定您刚刚设置为默认值的相同操作. 您可能想要做的只是省略$ErrorActionPreference = "Stop"

于 2013-10-10T01:06:03.020 回答
6

唯一缺少的是breakCatch 块中的 -statement。如果您不指示,Powershell 不会停止脚本。

try {
    get-content "c:\GarbageFileName.txt" -ErrorAction stop
}
catch {
    write-output "in catch, I want it to stop now"
    break
}
write-output "try-catch finished, script is continuing"

还有一个小附录,以防它对您有所帮助:使用finally,您可以添加一些始终执行的代码行,无论是否引发异常。

try {
    get-content "c:\GarbageFileName.txt" -ErrorAction stop
}
catch {
    write-output "in catch, I want it to stop now"
    break
}
finally {
    #do some stuff here that is executed even after the break-statement, for example:
    Set-Content -Path "f:\GarbageFileName.txt" -Value $null 
}

#the line below is executed only if the error didn't happen
write-output "try-catch finished, script is continuing"
于 2013-10-09T22:10:02.447 回答
2

Try-Catch 将捕获一个异常并允许您处理它,也许处理它意味着停止执行......但它不会隐式地这样做。它实际上会消耗异常,除非你重新抛出它。但是您的问题比这更简单- try 块优先-ErrorAction stop于 get-content cmdlet 中的 。因此,您不会停止执行,而是被带到Catch块并继续,因为在 catch 块中没有错误处理。

尝试从脚本中删除 try-catch 逻辑,并允许 cmdlet 出错:

get-content "c:\GarbageFileName.txt" -ErrorAction stop
write-output "You won't reach me if GarbageFileName doesn't exist."

你应该得到未达到的执行结果write-output

PS C:\> .\so-test.ps1
Get-Content : Cannot find path 'C:\GarbageFileName.txt' because it does not exist.
At C:\so-test.ps1:2 char:12
+ get-content <<<<  "c:\GarbageFileName.txt" -ErrorAction stop
    + CategoryInfo          : ObjectNotFound: (C:\GarbageFileName.txt:String) [Get-Content], ItemNotFoundException
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
于 2013-10-09T21:30:30.843 回答