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:
- Running the cmdlets with -ErrorAction Ignore
- Running the cmdlets with -ErrorAction SilentlyContinue
- Running the cmdlets inside try {} catch {}
- Running the cmdlets inside try {} catch {} with -ErrorAction Stop
- Running the cmdlets with 2>$null following them
- Setting $ErrorActionPreference = "SilentlyContinue" before running the cmdlets
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.
CodePudding user response:
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($HashCode -and $Error[0].GetHashCode() -ne $HashCode) { $Error.RemoveAt(0) }
CodePudding user response:
Use the common -ErrorVariable
parameter in order to collect only the (non-terminating) errors directly emitted by a cmdlet (those that it internally 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.