Minkus
Minkus

Reputation: 462

Faulty PowerShell cmdlets filling up $Error automatic variable

In order to be informed when PowerShell Startup / Logon scripts running on remote computers have bugs, I tend to end scripts with the following:

If ($Error) {
    (Code that sends a notification email to system administrators attaching the contents of the $Error variable for troubleshooting)
}

This is a great 'tell tale' to pick up edge cases / bugs. However, I've found some basic built-in PowerShell cmdlets dump data into $Error even on successful runs - for example, try:

$Error.Clear()
Get-NetIPConfiguration
$Error

And you'll see a load of errors in $Error that are not shown during normal output but look like:

Get-NetRoute : No matching MSFT_NetRoute objects found by CIM query for instances of the ROOT/StandardCimv2/MSFT_NetRoute class on the CIM server: SELECT * FROM MSFT_NetRoute WHERE ((DestinationPrefix LIKE '0.0.0.0/0')) AND ((InterfaceAlias LIKE 'OpenVPN Wintun')). Verify query parameters and retry.

Get-NetConnectionProfile : No MSFT_NetConnectionProfile objects found with property 'InterfaceAlias' equal to 'Local Area Connection'. Verify the value of the property and
retry.

or

$Error.Clear()
Get-NetIPAddress
$Error

will return:

“Infinite : The term '“Infinite' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.

(A nice little bug for Microsoft to solve at some point, doubtless!)

Since it's unlikely that the cmdlets will be fixed any time soon, is there a way to run these cmdlets without them clogging up $Error with their useless information?

This is not a duplicate of Powershell: How can I stop errors from being displayed in a script? since that covers errors that actually display in red on the PowerShell console during a 'failed' run of the cmdlet; this is about errors generated by some cmdlets in the background during an apparently 'successful' run of a cmdlet which for some reason only get written to the automatic $Error variable.

Nonetheless I have already tried a number of solutions suggested in that post:

I may be asking the impossible, but the way these cmdlets behave does make $Error very hard to use as an actual log, just want to know if I'm missing a trick.

I would like to be able to encapsulate buggy cmdlets in such a way that 'hidden' errors do not go into the automatic $Error variable.

Upvotes: 3

Views: 298

Answers (2)

mklement0
mklement0

Reputation: 439307

Use the common -ErrorVariable parameter in order to collect only the (non-terminating) errors directly emitted or intentionally passed through by a cmdlet (those that it internally silences or ignores will not be captured):

# $errs is a self-chosen variable; note that it must be specified WITHOUT $
Get-NetIPAddress -ErrorVariable errs

# $errs now contains any (non-terminating) errors emitted by the 
# Get-NetIPAddress call, as a [System.Collections.ArrayList] instance.
# (If no errors occurred, the list is empty).

Note: To also silence errors, combine -ErrorVariable errs with -ErrorAction SilentlyContinue (-ErrorAction SilentlyContinue does not work - see below).


The automatic $Error variable is designed to provide a session-wide log of all errors.

However, (script) cmdlets that deliberately ignore errors can avoid logging unnecessary errors by using -ErrorAction Ignore in internal calls - assuming that the errors are not only to be silenced, but also needn't be inspected.
(If errors need to be inspected after having collected them with -ErrorVariable, use of -ErrorAction Ignore is not an option, because it prevents error collection.)

The CDXML-based cmdlets from the NetTCPIP module, such as Get-NetIPAddress unfortunately use -ErrorAction SilentlyContinue in cases where -ErrorAction Ignore would suffice.
Conceivably, the cmdlet-generation code predates v3 of PowerShell, when the Ignore value was introduced.

Upvotes: 0

iRon
iRon

Reputation: 23763

I agree with @zett42' comment: I think you can't really prevent cmdlets from adding to $Error.
Also knowing that these "phantom errors" might already occur with a simple (Try/Catch) statement like:

Try { 1/0 } Catch {}

Anyways, you might consider to mark the last one and remove the errors added after that/ Like:

$HashCode = if ($Error) { $Error[0].GetHashCode() }
Get-NetIPAddress
While($Error -and $Error[0].GetHashCode() -ne $HashCode) { $Error.RemoveAt(0) }

Upvotes: 3

Related Questions