Making Error Records More Readable

by Nov 23, 2018

Whenever PowerShell encounters an error, it emits an Error Record with detailed information about the problem. Unfortunately, these objects are a bit cryptic and won’t show all of their information by default. To get to the beef, a function like the below is of invaluable help:

function ConvertFrom-ErrorRecord
{
  param
  (
    # we receive either a legit error record...
    [Management.Automation.ErrorRecord[]]
    [Parameter(
        Mandatory,ValueFromPipeline,
        ParameterSetName='ErrorRecord')]
    $ErrorRecord,
    
    # ...or a special stop exception which is raised by
    # cmdlets with -ErrorAction Stop
    [Management.Automation.ActionPreferenceStopException[]]
    [Parameter(
        Mandatory,ValueFromPipeline,
        ParameterSetName='StopException')]
    $Exception
  )
  
  

  process
  {
    # if we received a stop exception in $Exception, 
    # the error record is to be found inside of it
    # in all other cases, $ErrorRecord was received
    # directly
    if ($PSCmdlet.ParameterSetName -eq 'StopException')
    {
      $ErrorRecord = $Exception.ErrorRecord
    } 
    
    # compose a new object out of the interesting properties
    # found in the error record object
    $ErrorRecord | ForEach-Object { [PSCustomObject]@{
        Exception = $_.Exception.Message
        Reason    = $_.CategoryInfo.Reason
        Target    = $_.CategoryInfo.TargetName
        Script    = $_.InvocationInfo.ScriptName
        Line      = $_.InvocationInfo.ScriptLineNumber
        Column    = $_.InvocationInfo.OffsetInLine
      }
    }
  }
}

With it, you can decipher the error information collected in $error:

 
PS C:\> $Error | ConvertFrom-ErrorRecord | Out-GridView
 

You can as well use it in try..catch blocks:

try
{
  Get-Service -Name foo -ErrorAction Stop

}
catch
{
  $_ | ConvertFrom-ErrorRecord
}

The result will be similar to this:

 
Exception : Cannot find any service with service name 'foo'.
Reason    : ServiceCommandException
Target    : foo
Script    : 
Line      : 5
Column    : 3 
 

And you can it even with the –ErrorVariable common parameter which collects all error records that occur while a cmdlet runs:

$r = Get-ChildItem -Path $env:windir -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue -ErrorVariable test
$test | ConvertFrom-ErrorRecord

The result again will be similar to this:

 
Exception : Access to the path 'C:\Windows\AppCompat\Appraiser\Telemetry' is 
            denied.
Reason    : UnauthorizedAccessException
Target    : C:\Windows\AppCompat\Appraiser\Telemetry
Script    : 
Line      : 3
Column    : 6

Exception : Access to the path 'C:\Windows\AppCompat\Programs' is denied.
Reason    : UnauthorizedAccessException
Target    : C:\Windows\AppCompat\Programs
Script    : 
Line      : 3
Column    : 6

Exception : Access to the path 'C:\Windows\CSC\v2.0.6' is denied.
Reason    : UnauthorizedAccessException
Target    : C:\Windows\CSC\v2.0.6
Script    : 
Line      : 3
Column    : 6 

...
 

Twitter This Tip! ReTweet this Tip!