Monday, 20 May 2013

Catching dynamic exception types in PowerShell [migrated]

Catching dynamic exception types in PowerShell [migrated]

I'm working on a PowerShell library that automates some network management operations. Some of these operations have arbitrary delays, and each can fail in unique ways. To handle these delays gracefully, I'm creating a generic retry function that has three main purposes:
Execute an arbitrary command (with parameters)
If it fails in a recognized way, try it again, up to some limit
If it fails in an unexpected way, bail and report
The problem is item #2. I want to be able to specify the expected exception type for the command. How can I do this in PowerShell?
Here's my function:
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)
}
I call it like this:
$result = Retry-Command -Name = "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
But this is the result:
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
This seems to be saying that the type of [System.Management.Automation.RuntimeException] is not itself a [System.Exception], but is instead a [System.RuntimeType] which makes sense.
So, how do I specify the type of the exception to be caught?

No comments:

Post a Comment