Reputation: 333
Is there a convenient way to catch types of exceptions and inner exceptions for try-catch purposes?
Example code:
$a = 5
$b = Read-Host "Enter number"
$c = $a / $b #error if $b -eq 0
$d = get-content C:\I\Do\Not\Exist
Row #3 will generate a runtime error with an inner exception (EDIT: fixed this command $Error[1].Exception.InnerException.GetType()), row #4 will generate a "standard"(?) type of exception ($Error[0].Exception.GetType()).
Is it possible to get the desired result from both of these with the same line of code?
Ad1: error from row 3
At -path-:3 char:1
+ $c = $a / $b #error if $b -eq 0
+ ~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Ad2: error from row 4
get-content : Cannot find path 'C:\I\Do\Not\Exist' because it does not exist.
At -path-:4 char:6
+ $d = get-content C:\I\Do\Not\Exist
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\I\Do\Not\Exist:String)
[Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Edit: To make it clear, I want the result to return DivideByZeroException and ItemNotFoundException in some way
Upvotes: 13
Views: 19481
Reputation: 6363
Just wanted to add that you can create a sorted list of exception types like so:
function Get-Exceptions {
[OutputType([String[]])]
[String[]]$Exceptions = [AppDomain]::CurrentDomain.GetAssemblies() | foreach {
try {
$_.GetExportedTypes().BaseType | where { $_.Fullname -match 'Exception' }
} catch {}
}
return $Exceptions | Sort-Object -Unique
}
It can be used to find the appropriate exception type like so:
$Exceptions = Get-Exceptions
Write-Output $Exceptions
Upvotes: 0
Reputation: 17035
First of all, you can explicitly catch specific exception types:
$ErrorActionPreference = "Stop"
try {
1 / 0
}
catch [System.DivideByZeroException] {
$_.Exception.GetType().Name
}
try {
Get-Item "c:\does-not-exist"
}
catch [System.Management.Automation.ItemNotFoundException] {
$_.Exception.GetType().Name
}
The DivideByZeroException
is basically just the InnerException of RuntimeException
, and theoretically, the InnerExceptions could be endlessly nested:
catch {
$exception = $_.Exception
do {
$exception.GetType().Name
$exception = $exception.InnerException
} while ($exception)
}
BUT you can handle RuntimeException
as a special case. Even PowerShell does so. Look at the first code example. The catch-block is reached even though the type of the inner exception is specified.
You could do something similar yourself:
catch {
$exception = $_.Exception
if ($exception -is [System.Management.Automation.RuntimeException] -and $exception.InnerException) {
$exception = $exception.InnerException
}
$exception.GetType().Name
}
NOTE that you need one try-catch per command, if you want to catch both exceptions. Else the 2nd will not be executed if the 1st one fails. Also you have to specify $ErrorActionPreference
to "Stop"
to catch also non-terminating exceptions.
Upvotes: 13