Removing A Specific Error from the $Error Collection:

This is my first post, and I really struggled with what to write.  I didn’t want to write something heavy straight away.  So, I decided to write about an interesting observation.  In this case, a neat error handling trick, something that’s been there the whole time, but I never thought of leveraging.

Back in the VBScript days a common pattern was to set On Error Resume Next, run some statement(s) then check if Err.Number <> 0. Followed by some handling code, often a simple echo, then Err.Clear.

The Err object is a simple mechanism to test for problems, but it only stores the last error.  PowerShell’s more robust error handling includes Try/Catch which is similar albeit more eloquent.  Both Try/Catch & Err must be present where errors are expected.  However, PowerShell’s $Error collection is different offering an ability to analyze errors post-run.  $Error can be used to identify unexpected errors that may be the subject of further improvements etc…

Recently, while debugging issues in a very busy script, I wrote $Error to a log file.  This had always worked “well enough”, however, in this case there was too much noise to make use of the output.

I needed to retain unexpected errors while discarding the handled and/or unimportant ones.  It’s reminiscent of VBS’s Err.Clear, but I can’t use PowerShell’s $Error.Clear() because it will clear the entire collection.  Instead I need to tactically remove records from the collection.

Luckily $Error, is an instance of System.Collections.ArrayList.  ArrayList is a really useful class, and well documented elsewhere, so, I won’t get in-depth on it here.  However, for this case ArrayList’s .Remove() method can remove a specific object from the collection when passed that object.

For Example:

[collections.ArrayList]$arrList = @( "one","two","three" )
$arrList.Remove( "two" )

Bringing this back to the $Error collection, you can remove the last error with something like:

$Error.Remove($Error[0])

The point in the above example is that $Error[0] is the last ErrorRecord object, so you could go with a pattern like:

#Start with an empty error collection:
$Error.Clear()
Try
{
    #Just to get an error:
    Remove-Variable DoesNotExist -ErrorAction Stop
}
Catch
{
    Write-Host "Caught error, current count: $($Error.Count)"
    # $Error.Remove($_)
    $Error.Remove($Error[0])
    Write-Host "Count after removing last error: $($Error.Count)"
}

One thing to notice is $Error.Remove( $_ ) doesn’t work! That’s a little shocking considering above PoSh 3.0 $_ in a catch block should be identical to $Error[0]. I’m guessing there’s some kind of referencing going on, but I’ll have to work on figuring that out.

At any rate, you can use this trick to keep your error collection as clean as possible, potentially making post-analysis a lot easier.

So that’s it for my very first post. Let me know what you think in the comments, I’d love to hear from you.

Advertisement