Function Resolve-Error { <# .SYNOPSIS Enumerate error record details. .DESCRIPTION Enumerate an error record, or a collection of error record, properties. By default, the details for the last error will be enumerated. .PARAMETER ErrorRecord The error record to resolve. The default error record is the lastest one: $global:Error[0]. This parameter will also accept an array of error records. .PARAMETER Property The list of properties to display from the error record. Use "*" to display all properties. Default list of error properties is: Message, FullyQualifiedErrorId, ScriptStackTrace, PositionMessage, InnerException Below is a list of all of the possible available properties on the error record: Error Record: Error Invocation: Error Exception: Error Inner Exception(s): $_ $_.InvocationInfo $_.Exception $_.Exception.InnerException ------------- ----------------- ---------------- --------------------------- writeErrorStream MyCommand ErrorRecord Data PSMessageDetails BoundParameters ItemName HelpLink Exception UnboundArguments SessionStateCategory HResult TargetObject ScriptLineNumber StackTrace InnerException CategoryInfo OffsetInLine WasThrownFromThrowStatement Message FullyQualifiedErrorId HistoryId Message Source ErrorDetails ScriptName Data StackTrace InvocationInfo Line InnerException TargetSite ScriptStackTrace PositionMessage TargetSite PipelineIterationInfo PSScriptRoot HelpLink PSCommandPath Source InvocationName HResult PipelineLength PipelinePosition ExpectingInput CommandOrigin DisplayScriptPosition .PARAMETER GetErrorRecord Get error record details as represented by $_ Default is to display details. To skip details, specify -GetErrorRecord $false .PARAMETER GetErrorInvocation Get error record invocation information as represented by $_.InvocationInfo Default is to display details. To skip details, specify -GetErrorInvocation $false .PARAMETER GetErrorException Get error record exception details as represented by $_.Exception Default is to display details. To skip details, specify -GetErrorException $false .PARAMETER GetErrorInnerException Get error record inner exception details as represented by $_.Exception.InnerException. Will retrieve all inner exceptions if there is more then one. Default is to display details. To skip details, specify -GetErrorInnerException $false .EXAMPLE Resolve-Error Get the default error details for the last error .EXAMPLE Resolve-Error -ErrorRecord $global:Error[0,1] Get the default error details for the last two errors .EXAMPLE Resolve-Error -Property * Get all of the error details for the last error .EXAMPLE Resolve-Error -Property InnerException Get the "InnerException" for the last error .EXAMPLE Resolve-Error -GetErrorInvocation $false Get the default error details for the last error but exclude the error invocation information .NOTES Borrowed from https://stackoverflow.com/questions/795751/can-i-get-detailed-exception-stacktrace-in-powershell Please return when done. #> [CmdletBinding()] Param ( [Parameter(Mandatory=$false, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [ValidateNotNullorEmpty()] [array]$ErrorRecord, [Parameter(Mandatory=$false)] [ValidateNotNullorEmpty()] [string[]]$Property = ('Message','InnerException','FullyQualifiedErrorId','ScriptStackTrace','PositionMessage'), [Parameter(Mandatory=$false)] [bool]$GetErrorRecord = $true, [Parameter(Mandatory=$false)] [bool]$GetErrorInvocation = $true, [Parameter(Mandatory=$false)] [bool]$GetErrorException = $true, [Parameter(Mandatory=$false)] [bool]$GetErrorInnerException = $true ) Begin { $logLead = (Get-LogLeadName) ## If function was called without specifying an error record, then choose the latest error that occured if (-not $ErrorRecord) { if ($global:Error.Count -eq 0) { # The `$Error collection is empty Write-Verbose "$logLead : global Error is empty." return } else { Write-Verbose "$logLead : found items in global Error collection. Getting first error." [array]$ErrorRecord = $global:Error[0] } } ## Define script block for selecting and filtering the properties on the error object [scriptblock]$selectProperty = { Param ( [Parameter(Mandatory=$true)] [ValidateNotNullorEmpty()] $InputObject, [Parameter(Mandatory=$true)] [ValidateNotNullorEmpty()] [string[]]$SelectedProperty ) Write-Verbose "$logLead : InputObject [$InputObject]" Write-Verbose "$logLead : SelectedProperty [$SelectedProperty]" [string[]]$objectProperty = $InputObject | Get-Member -MemberType *Property | Select-Object -ExpandProperty Name foreach ($prop in $SelectedProperty) { if ($prop -eq '*') { [string[]]$propertySelection = $objectProperty break } elseif ($objectProperty -contains $prop) { [string[]]$propertySelection += $prop } } return $propertySelection } # Initialize variables to avoid error if 'Set-StrictMode' is set $logErrorRecordMsg = $null $logErrorInvocationMsg = $null $logErrorExceptionMsg = $null $logErrorMessageTmp = $null $logInnerMessage = $null } Process { foreach ($errRecord in $ErrorRecord) { ## Capture Error Record if ($GetErrorRecord) { Write-Verbose "$logLead : Capture Error Record" [string[]]$selectedProperties = Invoke-Command -ScriptBlock $selectProperty -ArgumentList $errRecord, $Property $logErrorRecordMsg = $errRecord | Select-Object -Property $selectedProperties } ## Error Invocation Information if ($GetErrorInvocation) { if ($errRecord.InvocationInfo) { Write-Verbose "$logLead : Get Error Invocation Information" [string[]]$selectedProperties = Invoke-Command -ScriptBlock $selectProperty -ArgumentList $errRecord.InvocationInfo, $Property $logErrorInvocationMsg = $errRecord.InvocationInfo | Select-Object -Property $selectedProperties } } ## Capture Error Exception if ($GetErrorException) { if ($errRecord.Exception) { Write-Verbose "$logLead : Capture Error Exception" [string[]]$selectedProperties = Invoke-Command -ScriptBlock $selectProperty -ArgumentList $errRecord.Exception, $Property $logErrorExceptionMsg = $errRecord.Exception | Select-Object -Property $selectedProperties } } ## Display properties in the correct order if ($Property -eq '*') { # If all properties were chosen for display, then arrange them in the order # the error object displays them by default. Write-Verbose "$logLead : Display all properties" if ($logErrorRecordMsg) {[array]$logErrorMessageTmp += $logErrorRecordMsg } if ($logErrorInvocationMsg) {[array]$logErrorMessageTmp += $logErrorInvocationMsg} if ($logErrorExceptionMsg) {[array]$logErrorMessageTmp += $logErrorExceptionMsg } } else { # Display selected properties in our custom order Write-Verbose "$logLead : Display selected properties in custom order" if ($logErrorExceptionMsg) {[array]$logErrorMessageTmp += $logErrorExceptionMsg } if ($logErrorRecordMsg) {[array]$logErrorMessageTmp += $logErrorRecordMsg } if ($logErrorInvocationMsg) {[array]$logErrorMessageTmp += $logErrorInvocationMsg} } if ($logErrorMessageTmp) { $logErrorMessage = 'Error Record:' $logErrorMessage += "`n-------------" $logErrorMsg = $logErrorMessageTmp | Format-List | Out-String $logErrorMessage += $logErrorMsg } ## Capture Error Inner Exception(s) if ($GetErrorInnerException) { if ($errRecord.Exception -and $errRecord.Exception.InnerException) { Write-Verbose "$logLead : Capture Error Inner Exception" $logInnerMessage = 'Error Inner Exception(s):' $logInnerMessage += "`n-------------------------" $errorInnerException = $errRecord.Exception.InnerException $Count = 0 while ($errorInnerException) { $innerExceptionSeperator = '~' * 40 [string[]]$selectedProperties = Invoke-Command -ScriptBlock $selectProperty -ArgumentList $errorInnerException, $Property $logErrorInnerExceptionMsg = $errorInnerException | Select-Object -Property $selectedProperties | Format-List | Out-String if ($Count -gt 0) { $logInnerMessage += $innerExceptionSeperator } $logInnerMessage += $logErrorInnerExceptionMsg $Count++ $errorInnerException = $errorInnerException.InnerException } } } if ($logErrorMessage) { $output += $logErrorMessage } if ($logInnerMessage) { $output += $logInnerMessage } Write-Verbose "$logLead : Write output" Write-Host $output Write-Verbose "$logLead : Cleanup variables" if (Test-Path -Path 'variable:Output' ) { Clear-Variable -Name output } if (Test-Path -Path 'variable:LogErrorMessage' ) { Clear-Variable -Name logErrorMessage } if (Test-Path -Path 'variable:logInnerMessage' ) { Clear-Variable -Name logInnerMessage } if (Test-Path -Path 'variable:logErrorMessageTmp') { Clear-Variable -Name logErrorMessageTmp } } } End {} }