如果出现错误,如何使用try ... catch并让我的脚本停止?

时间:2013-10-09 21:13:57

标签: powershell

我试图让我的脚本停止,如果它遇到错误,并使用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个答案,或者有足够的声誉来投票给那些我不情愿选择的答案,或者以某种方式表示感谢!

3 个答案:

答案 0 :(得分:10)

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对象。你可以做很多事情,这里有一个全面的主题,但是你可以通过googling System.Management.Automation.ErrorRecord 获得更多关于语法的信息。以下是我的一个脚本示例(来自执行 $ query 变量中针对SQL Server数据库定义的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时,我正在使用 $ _ ,我刚才说的包含与尝试中捕获的终止错误相关联的ErrorRecord对象阻止。我们的想法是定制一些错误输出,同时使用默认ErrorRecord的部分,将它们分配给自定义ErrorRecord的相应属性。
  • 只有在函数或脚本开头声明[CmdletBinding()]时,
  • $ PSCmdlet 才可用。否则,您只需使用throw $ErrorRecord来抛出自定义错误。但是,如果使用 $ PSCmdlet.ThrowTerminatingError ,结果将更加Cmdlet风格。 ( throw 将从生成错误的函数中回吐该行,而 $ PSCmdlet.ThrowTerminatingError 将为您提供来自使用该函数的调用上下文的行。它是难以用一种有意义的方式描述而不会过于复杂,但如果你试验它,你会明白我的意思。)

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

答案 1 :(得分:5)

唯一缺少的是Catch-block中的break - 语句。如果您没有指示脚本,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"

答案 2 :(得分:1)

Try-Catch将捕获异常并允许您处理它,并且可能处理它意味着停止执行......但它不会隐含地执行此操作。它实际上会消耗异常,除非你重新抛出它。但是您的问题比这更简单 - try块优先于get-content cmdlet中的-ErrorAction stop。因此,不是停止执行,而是进入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