在PowerShell中捕获动态异常类型

时间:2013-05-21 01:10:58

标签: powershell

我正在开发一个自动执行某些网络管理操作的PowerShell库。其中一些操作具有任意延迟,并且每个操作都可能以独特的方式失败。为了优雅地处理这些延迟,我正在创建一个通用的重试函数,它有三个主要目的:

  1. 执行任意命令(带参数)
  2. 如果以可识别的方式失败,请再次尝试,达到某种限制
  3. 如果以意外方式失败,请保释并报告
  4. 问题是第2项。我希望能够为命令指定预期的异常类型。如何在PowerShell中执行此操作?

    这是我的功能:

    Function Retry-Command {
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory=$True, Position=0)]
            [String] $name,
    
            [Parameter(Mandatory=$True, Position=1)]
            [String] $scriptBlock,
    
            [String[]] $argumentList,
            [Int] $maxAttempts=3,
            [Int] $retrySeconds=10,
            [System.Exception] $retryException=[System.Management.Automation.RuntimeException]
        )
        $attempts = 1
        $keepTrying = $True
        $cmd = [ScriptBlock]::Create($scriptblock)
        do {
            try {
                &$cmd @argumentList
                $keepTrying = $False
                Write-Verbose "Command [$commandName] succeeded after $attmpts attempts."
            } catch [$retryException] {
                $msg = "Command [$commandName] failed. Attempt $attempts of $maxAttempts."
                Write-Verbose $msg;
                if ($maxAttempts -gt $attempts) {
                    Write-Debug "Sleeping $retrySeconds"
                    Start-Sleep -Seconds $retrySeconds
                } else {
                    $keepTrying = $False
                    Write-Debug "Reached $attempts attempts. Re-raising exception."
                    Throw $_.Exception
                }
            } catch [System.Exception] {
                $keepTrying = $False
                $msg = "Unexpected exception while executing command [$CommandName]: "
                Write-Error $msg + $_.Exception.ToString()
                Throw $_.Exception
            } finally {
                $attempts += 1
            }
        } while ($True -eq $keepTrying)
    }
    

    我称之为:

    $result = Retry-Command -Name = "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
    

    但这是结果:

    Retry-Command : Cannot process argument transformation on parameter 'retryException'. 
    Cannot convert the "System.Management.Automation.RuntimeException" value of type "System.RuntimeType" to type "System.Exception".
    At Foo.ps1:111 char:11
    + $result = Retry-Command <<<<  -Name "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
        + CategoryInfo          : InvalidData: (:) [Retry-Command], ParameterBindin...mationException
        + FullyQualifiedErrorId : ParameterArgumentTransformationError,Retry-Command
    

    这似乎是说[System.Management.Automation.RuntimeException]类型本身不是[System.Exception],而是[System.RuntimeType],这是有道理的。

    那么,如何指定要捕获的异常类型?

1 个答案:

答案 0 :(得分:2)

不可能将变量用作捕获条件,它必须是类型对象(或其他东西),其他一切都会给你一个错误。解决方法是这样的:

#You can get the name of the exception using the following (or .Name for just the short name)
#PS > $myerr.Exception.GetType().Fullname
#System.UnauthorizedAccessException


function test {
    param(
    #Validate that specified name is a class that inherits from System.Exception base class
    [ValidateScript({[System.Exception].IsAssignableFrom([type]$_)})]
    $ExceptionType
    )

    try {
        #Test-script, Will throw UnauthorizedAccessException when not run as admin
        (Get-Content C:\test.txt) | % { $_ -replace 'test','lol' } | Set-Content C:\test.txt
    }
    catch [System.Exception] {
        #Check if exceptiontype is equal to the value specified in exceptiontype parameter
        if($_.Exception.GetType() -eq ([type]$ExceptionType)) {
            "Hello. You caught me"
        } else {
        "Uncaught stuff: $($_.Exception.Gettype())"
        }
    }
}

一些测试。一个是不存在的类型,然后是非异常类型,最后是一个工作的

PS > test -ExceptionType system.unaut
test : Cannot validate argument on parameter 'ExceptionType'. Cannot convert the "system.unaut" val
ue of type "System.String" to type "System.Type".
At line:1 char:21
+ test -ExceptionType system.unaut
+                     ~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [test], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,test


PS > test -ExceptionType String
test : Cannot validate argument on parameter 'ExceptionType'. The "[System.Exception].IsAssignableF
rom([type]$_)" validation script for the argument with value "String" did not return true. Determin
e why the validation script failed and then try the command again.
At line:1 char:21
+ test -ExceptionType String
+                     ~~~~~~
    + CategoryInfo          : InvalidData: (:) [test], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,test


PS > test -ExceptionType UnauthorizedAccessException
Hello. You caught me