title: Catching dynamic exception types in PowerShell
body: <p>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:</p>
  
  <ol>
  <li>Execute an arbitrary command (with parameters)</li>
  <li>If it fails in a recognized way, try it again, up to some limit</li>
  <li>If it fails in an unexpected way, bail and report</li>
  </ol>
  
  <p>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?</p>
  
  <p>Here's my function:</p>
  
  <pre><code>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 {
              &amp;$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)
  }
  </code></pre>
  
  <p>I call it like this:</p>
  
  <pre><code>$result = Retry-Command -Name = "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
  </code></pre>
  
  <p>But this is the result:</p>
  
  <pre><code>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 &lt;&lt;&lt;&lt;  -Name "Foo the bar" -ScriptBlock $cmd -ArgumentList $cmdArgs
      + CategoryInfo          : InvalidData: (:) [Retry-Command], ParameterBindin...mationException
      + FullyQualifiedErrorId : ParameterArgumentTransformationError,Retry-Command
  </code></pre>
  
  <p>This seems to be saying that the <em>type</em> of <code>[System.Management.Automation.RuntimeException]</code> is not itself a <code>[System.Exception]</code>, but is instead a <code>[System.RuntimeType]</code> which makes sense.</p>
  
  <p>So, how do I specify the type of the exception to be caught?</p>