175 lines
11 KiB
PowerShell
175 lines
11 KiB
PowerShell
function Write-ExceptionToStringBuilder {
|
|
<#
|
|
.SYNOPSIS
|
|
This function should be used by Write-ErrorObject to convert the inner exception object(s) to a form that can be used for printing out.
|
|
|
|
.PARAMETER Exception
|
|
The exception being processed. Can be an InnerException to a parent object.
|
|
|
|
.PARAMETER ShortMessageSB
|
|
This stringbuilder is used to highlight selected data for the given exception
|
|
|
|
.PARAMETER ExceptionSB
|
|
This stringbuilder is used to append data for the given exception.
|
|
|
|
.PARAMETER StackTraceSB
|
|
This stringbuilder is used to append stack trace data for the given exception.
|
|
|
|
.PARAMETER SelectedProperties
|
|
This object contains selected properties that may be worth investigating
|
|
|
|
.OUTPUTS
|
|
This function returns a dereferenceable array of the ShortMessage stringbuilder, the Exception stringbuilder, the StackTrace stringbuilder, and the dictionary of selected properties.
|
|
#>
|
|
[CmdletBinding()]
|
|
[OutputType([object[]])]
|
|
param (
|
|
[System.Exception]$Exception,
|
|
[System.Text.StringBuilder]$ShortMessageSB,
|
|
[System.Text.StringBuilder]$ExceptionSB,
|
|
[System.Text.StringBuilder]$StackTraceSB,
|
|
[int]$InnerExceptionDepth,
|
|
[Object]$SelectedProperties
|
|
)
|
|
if ($null -eq $SelectedProperties) {
|
|
$SelectedProperties = @{}
|
|
}
|
|
if ($null -eq $ShortMessageSB) {
|
|
$ShortMessageSB = New-Object System.Text.StringBuilder
|
|
}
|
|
if ($null -eq $ExceptionSB) {
|
|
$ExceptionSB = New-Object System.Text.StringBuilder
|
|
}
|
|
if ($null -eq $StackTraceSB) {
|
|
$StackTraceSB = New-Object System.Text.StringBuilder
|
|
}
|
|
|
|
$selectedPropertiesNewKey = "Exception"
|
|
if ($InnerExceptionDepth -gt 0) {
|
|
$selctedPropertiesNewKey = "InnerException #$InnerExceptionDepth"
|
|
}
|
|
$selectedPropertiesNewObject = @{}
|
|
|
|
$padLeftSize = ($InnerExceptionDepth * 2)
|
|
$paddingSpaces = "$(''.PadLeft($padLeftSize))"
|
|
|
|
if ($null -ne $exception) {
|
|
if ($null -ne $exception.Reason) {
|
|
Write-Host "recursing exception.reason"
|
|
$ShortMessageSB, $ExceptionSB, $StackTraceSB, $SelectedProperties = (Write-ExceptionToStringBuilder -Exception $exception.Reason -InnerExceptionDepth ($InnerExceptionDepth + 1) -ShortMessageSB $ShortMessageSB -ExceptionSB $ExceptionSB -StackTraceSB $StackTraceSB -SelectedProperties $scriptProperties)
|
|
}
|
|
if ($null -ne $exception.InnerException) {
|
|
$ShortMessageSB, $ExceptionSB, $StackTraceSB, $SelectedProperties = (Write-ExceptionToStringBuilder -Exception $exception.InnerException -InnerExceptionDepth ($InnerExceptionDepth + 1) -ShortMessageSB $ShortMessageSB -ExceptionSB $ExceptionSB -StackTraceSB $StackTraceSB -SelectedProperties $scriptProperties)
|
|
}
|
|
if ($exception.WasThrownFromThrowStatement) {
|
|
$ShortMessageSB.Insert(0,"[This error was thrown via throw]")
|
|
}
|
|
$ExceptionSB.Append($paddingSpaces).AppendLine("Exception of type $($exception.GetType().FullName) thrown") | Out-Null
|
|
$ExceptionSB.Append($paddingSpaces).AppendLine("Message: $($exception.Message)") | Out-Null
|
|
if (![string]::IsNullOrWhiteSpace($exception.StackTrace)) {
|
|
if ($InnerExceptionDepth -eq 0) {
|
|
$StackTraceSB.AppendLine("---------Base Exception Stacktrace:") | Out-Null
|
|
} else {
|
|
$StackTraceSB.AppendLine("---------Inner (depth: $InnerExceptionDepth) Stacktrace:") | Out-Null
|
|
}
|
|
$StackTraceSB.AppendLine($exception.StackTrace) | Out-Null
|
|
}
|
|
|
|
$stringRecords = 'HelpLink','ItemName','ObjectName','ErrorId','ParamName','CommandName','ParameterName','Source','HelpTopic','RequiresShellPath','TypeName','RedirectLocation','Error','Label','AssemblyName','RequiresShellId','TransportMessage','HelpCategory'
|
|
$simpleRecords = 'HResult','TypeSpecified','ErrorCode','CallDepth','RequiresPSVersion','WasThrownFromThrowStatement','ParameterType'
|
|
$complexRecords = @(
|
|
<#System.Object#>'ActualValue'
|
|
<#System.Object#>'Argument'
|
|
<#System.Management.Automation.PSObject#>'SerializedRemoteException'
|
|
<#System.Management.Automation.InvocationInfo#>'CommandInvocation'
|
|
<#System.Management.Automation.ErrorRecord#>'ErrorRecord'
|
|
<#System.Management.Automation.PSObject#>'SerializedRemoteInvocationInfo'
|
|
<#System.Management.Automation.ProviderInvocationException#>'ProviderInvocationException'
|
|
<#System.Management.Automation.Language.ScriptExtent#>'DisplayScriptPosition'
|
|
<#System.Management.Automation.SessionStateCategory#>'SessionStateCategory'
|
|
<#System.Reflection.MethodBase#>'TargetSite'
|
|
<#System.Management.Automation.ProviderInfo#>'ProviderInfo'
|
|
)
|
|
$complexArrayRecords = @(
|
|
<#System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Management.Automation.ProviderInfo, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]#>'PossibleMatches'
|
|
<#System.Collections.ObjectModel.ReadOnlyCollection`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]#>'MissingPSSnapIns'
|
|
<#System.Management.Automation.PSDataCollection`1[[System.Management.Automation.ErrorRecord, System.Management.Automation, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]#>'ErrorRecords'
|
|
)
|
|
|
|
$ExceptionSB.AppendLine("$($paddingSpaces)Exception Object Data:") | Out-Null
|
|
foreach ($propertyName in $stringRecords) {
|
|
if (![string]::IsNullOrWhiteSpace($exception.$propertyName)) {
|
|
$ExceptionSB.AppendLine("$paddingSpaces$propertyName : $($exception.$propertyName)") | Out-Null
|
|
}
|
|
}
|
|
|
|
foreach ($propertyName in $simpleRecords) {
|
|
if (($null -ne $exception.$propertyName) -and ($false -ne $exception.$propertyName)) {
|
|
$ExceptionSB.AppendLine("$paddingSpaces$propertyName : $(($exception.$propertyName).ToString())") | Out-Null
|
|
}
|
|
}
|
|
foreach ($propertyName in $complexRecords) {
|
|
<#
|
|
try {
|
|
if ($null -ne $exception.$propertyName) {
|
|
$value = ConvertTo-Json $exception.$propertyName -Depth 10
|
|
$ExceptionSB.AppendLine("$paddingSpaces$propertyName : $value")
|
|
}
|
|
} catch {
|
|
Write-Warning "Error while attempting to transform error object. This code is untested in some places because the exceptions haven't been seen before."
|
|
#>
|
|
if ($null -ne $exception.$propertyName) {
|
|
Write-information "The value with key [$propertyName] has been attached to the complex data return object for evaluation."
|
|
$selectedPropertiesNewObject[$propertyName] = $exception.$propertyName
|
|
}
|
|
<#
|
|
# Error members were captured with this:
|
|
# $b = [System.Management.Automation.ParameterBindingException].Assembly.GetExportedTypes().Where({[System.Exception].IsAssignableFrom($_)})
|
|
# $b.GetProperties().Name | Sort-Object -Unique | Set-Clipboard
|
|
# $c = $b.GetProperties()
|
|
# $d = @{};foreach ($property in $c) { if ($null -eq $d[$property.Name]) { $d[$property.Name] = $property } }
|
|
# foreach ($property in $c) { if ($d[$property.Name].PropertyType -ne $property.PropertyType) { Write-Host $property.Name + " " + $property.PropertyType + " " + $d[$property.Name].PropertyType } }
|
|
# $e = @();foreach ($key in $d.PSObject.Properties["Keys"].Value) { $value = $d[$key]; if ($null -ne $value) { if ($value.PropertyType.FullName -eq 'System.String') { $e += "if (![string]::IsNullOrWhiteSpace(`$exception.$key)) { `n `$ExceptionSB.Append(`$paddingSpaces)`n #$($value.PropertyType.FullName)`n `$ExceptionSB.AppendLine(`"$key : `$(`$exception.$Key)`")`n}"} else {$e += "if (`$null -eq `$exception.$key) { `n `$ExceptionSB.Append(`$paddingSpaces)`n #$($value.PropertyType.FullName)`n `$ExceptionSB.AppendLine(`"$key : `$(`$exception.$Key)`")`n}"} } }; $e | Set-Clipboard
|
|
# This let me get the names of the System.Management.Automation.*Exception properties
|
|
# I did not write full translators for each item, so if you need those, you will need to expand this section
|
|
Write-Host $_.Exception.Message
|
|
Write-Host $_.ToString()
|
|
}
|
|
}
|
|
#>
|
|
|
|
foreach ($propertyName in $complexRecords) {
|
|
<#
|
|
try {
|
|
if ($null -ne $exception.$propertyName) {
|
|
$value = ConvertTo-Json $exception.$propertyName -Depth 10
|
|
$ExceptionSB.AppendLine("$paddingSpaces$propertyName : $value")
|
|
}
|
|
} catch {
|
|
Write-Warning "Error while attempting to transform error object. This code is untested in some places because the exceptions haven't been seen before."
|
|
#>
|
|
if ($null -ne $exception.$propertyName) {
|
|
Write-information "The value with key [$propertyName] has been attached to the complex data return object for evaluation."
|
|
$selectedPropertiesNewObject[$propertyName] = $exception.$propertyName
|
|
}
|
|
<#
|
|
# Error members were captured with this:
|
|
# $b = [System.Management.Automation.ParameterBindingException].Assembly.GetExportedTypes().Where({[System.Exception].IsAssignableFrom($_)})
|
|
# $b.GetProperties().Name | Sort-Object -Unique | Set-Clipboard
|
|
# $c = $b.GetProperties()
|
|
# $d = @{};foreach ($property in $c) { if ($null -eq $d[$property.Name]) { $d[$property.Name] = $property } }
|
|
# foreach ($property in $c) { if ($d[$property.Name].PropertyType -ne $property.PropertyType) { Write-Host $property.Name + " " + $property.PropertyType + " " + $d[$property.Name].PropertyType } }
|
|
# $e = @();foreach ($key in $d.PSObject.Properties["Keys"].Value) { $value = $d[$key]; if ($null -ne $value) { if ($value.PropertyType.FullName -eq 'System.String') { $e += "if (![string]::IsNullOrWhiteSpace(`$exception.$key)) { `n `$ExceptionSB.Append(`$paddingSpaces)`n #$($value.PropertyType.FullName)`n `$ExceptionSB.AppendLine(`"$key : `$(`$exception.$Key)`")`n}"} else {$e += "if (`$null -eq `$exception.$key) { `n `$ExceptionSB.Append(`$paddingSpaces)`n #$($value.PropertyType.FullName)`n `$ExceptionSB.AppendLine(`"$key : `$(`$exception.$Key)`")`n}"} } }; $e | Set-Clipboard
|
|
# This let me get the names of the System.Management.Automation.*Exception properties
|
|
# I did not write full translators for each item, so if you need those, you will need to expand this section
|
|
Write-Host $_.Exception.Message
|
|
Write-Host $_.ToString()
|
|
#>
|
|
}
|
|
}
|
|
}
|
|
|
|
$SelectedProperties.$selectedPropertiesNewKey = $selectedPropertiesNewObject
|
|
|
|
return @($ShortMessageSB, $ExceptionSB, $StackTraceSB, $SelectedProperties)
|
|
} |