Re-throwing errors

An error might be re-thrown within a catch block. This technique can be useful if a try block performs a number of dependent steps in a sequence where one or more might fail.

Re-throwing an error raised by a script can be as simple as using throw in a catch block:

try { 
    'Statement1' 
    throw 'Statement2' 
    'Statement3' 
} catch { 
    throw 
} 

ThrowTerminatingError might be used instead, depending on the desired behavior:

function Invoke-Something { 
    [CmdletBinding()] 
    param ( ) 
try { 'Statement1' throw 'Statement2' 'Statement3' } catch { $pscmdlet.ThrowTerminatingError($_) } }

When an error is re-thrown in this manner, the second instance of the error (within the catch block) is not written to either Error or an error variable. In cases where the error is re-thrown without modification, this doesn't present a problem.

If the re-thrown error attempts to add information, such as an error ID, the modified error record won't be available to error variables, as in the example:

try { 
    throw 'Error' 
} catch { 
    Write-Error -Exception $_.Exception -ErrorId 'GeneratedErrorId' -Category 'InvalidOperation' 
}

The error raised in the try block is added to the error variables but isn't displayed in a console (since it's been handled). The second error is displayed on the console but isn't added to error variables.

To resolve this problem, the new error record may return the original exception as an inner exception:

try { 
    throw 'Error' 
} catch {        
    $exception = [InvalidOperationException]::new( 
        $_.Exception.Message,
        $_.Exception 
    ) 
    Write-Error -Exception $exception -ErrorId 'GeneratedErrorId' -Category 'InvalidOperation' 
} 

In the case of exception and most, if not all, exception types, the first argument of the constructor is a message, and the second (optional) argument is an inner exception.

Using an inner exception has a number of advantages:

  • try-catch statements that test the outcome of the preceding snippet will trigger based on either the exception type or inner exception type
  • The other properties of the exception remain available (via the inner exception), such as the stack trace

When using an inner exception, it's important to note that PowerShell can't catch based on the inner exception type in most cases. The following example has three nested exceptions. PowerShell can't react to either the inner or intermediate exceptions:

try {
throw [InvalidOperationException]::new(
'OuterException',
[ArgumentException]::new(
'IntermediateException',
[UnauthorizedAccessException]::new('InnerException')
)

)
} catch [UnauthorizedAccessException] {
'Inner'
} catch [ArgumentException] {
'Intermediate'
} catch [InvalidOperationException] {
'Outer'
}

An exception to this rule is MethodInvocationException. PowerShell raises MethodInvocationException when a method call fails. For example, the DaysInMonth method of the DateTime type will fail if the month number isn't between 1 and 12. The exception raised by PowerShell is MethodInvocationException:

PS> [DateTime]::DaysInMonth(2019, 13)
Exception calling "DaysInMonth" with "2" argument(s): "Month must be between one and twelve.
Parameter name: month"
At line:1 char:2
+ [DateTime]::DaysInMonth(2019, 13)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentOutOfRangeException

However, it's possible to catch the inner exception, ArgumentOutOfRangeException, in this and similar cases:

try {
[DateTime]::DaysInMonth(2019, 13)
} catch [ArgumentOutOfRangeException] {
Write-Host 'Out of range'
}

When a command raises an error, and only the inner most exception is interesting, the InnerException property becomes useful. It allows access to each inner exception in turn. In the following example, the property is used to access the intermediate exception:

try {
throw [InvalidOperationException]::new(
'OuterException',
[ArgumentException]::new(
'IntermediateException',
[UnauthorizedAccessException]::new('InnerException')
)

)
} catch {
Write-Host $_.Exception.InnerException.Message
}

The Exception class (and all derived classes) include a GetBaseException method. This method provides simple access to the innermost exception and is useful when the number of nested exceptions is unknown or variable:

try {
throw [InvalidOperationException]::new(
'OuterException',
[ArgumentException]::new(
'IntermediateException',
[UnauthorizedAccessException]::new('InnerException')
)

)
} catch {
Write-Host $_.Exception.GetBaseException().Message
}

If and Switch statements may be used inside the catch block to further refine the handling of a specific error.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.90.131