I am actually enjoying my ride at 35,000 feet right
now. I am completely disconnected from
the world, listening to AD/DC and writing PowerShell code. I know, I am a bit weird at times but it pays
the bills.
This is day 1 or 5 in how to add error logs to your code.
Before I took off, I saw a request on the PowerShell
Facebook page about how to record the error objects created during a script run
when user accounts are not present. This
leads to a very interesting dilemma.
PowerShell records all errors in the current session as an error object. Give it a try.
PS C:\> Bad-Command
Bad-Command : The term
'Bad-Command' 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.
At line:1 char:1
+ Bad-Command
+ ~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound:
(Bad-Command:String) [], CommandNotFoundException
+ FullyQualifiedErrorId :
CommandNotFoundException
PS C:\> $Error[0] | GM
TypeName: System.Management.Automation.ErrorRecord
Name
MemberType Definition
----
---------- ----------
Equals
Method bool
Equals(System.Object obj)
GetHashCode
Method int
GetHashCode()
GetObjectData
Method void
GetObjectData(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context), void ISerializ...
GetType
Method type GetType()
ToString
Method string
ToString()
CategoryInfo
Property
System.Management.Automation.ErrorCategoryInfo CategoryInfo {get;}
ErrorDetails
Property System.Management.Automation.ErrorDetails
ErrorDetails {get;set;}
Exception
Property System.Exception
Exception {get;}
FullyQualifiedErrorId Property string FullyQualifiedErrorId {get;}
InvocationInfo
Property
System.Management.Automation.InvocationInfo InvocationInfo {get;}
PipelineIterationInfo Property System.Collections.ObjectModel.ReadOnlyCollection[int]
PipelineIterationInfo {get;}
ScriptStackTrace
Property string
ScriptStackTrace {get;}
TargetObject
Property System.Object
TargetObject {get;}
PSMessageDetails
ScriptProperty System.Object PSMessageDetails {get=& {
Set-StrictMode -Version 1; $this.Exception.InnerException.PSMessageDetails
};}
The dilemma that you will face is do you use this object or
create a customized one? Personally, it
depends on what I am trying to accomplish.
If I need the exact error object, then I utilized PowerShells built in
capability and I utilize the System.Management.Automation.ErrorRecord object
that is created. If I am looking at
creating more customized error messages, then I create the object myself.
There is another problem that we need to consider. When you create your own error object, you
can pipe it to Export-CSV and
utilize the –Append parameter to simply add your custom error object to
your error log. The error object created
by PowerShell is not a 2D object. It has
multiple levels of depth that a CSV file cannot store. Here is an example:
PS C:\> $Error[0] | Select *
PSMessageDetails :
Exception :
System.Management.Automation.CommandNotFoundException: The term 'Bad-Command'
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.
at System.Management.Automation.CommandDiscovery.LookupCommandInfo(String
commandName, CommandTypes commandTypes, SearchResolutionOptions
searchResolutionOptions, CommandOrigin commandOrigin, ExecutionContext
context)
at
System.Management.Automation.CommandDiscovery.LookupCommandProcessor(String
commandName, CommandOrigin commandOrigin, Nullable`1 useLocalScope)
at System.Management.Automation.ExecutionContext.CreateCommand(String
command, Boolean dotSource)
at System.Management.Automation.PipelineOps.AddCommand(PipelineProcessor
pipe, CommandParameterInternal[] commandElements, CommandBaseAst
commandBaseAst,
CommandRedirection[] redirections, ExecutionContext context)
at System.Management.Automation.PipelineOps.InvokePipeline(Object input,
Boolean ignoreInput, CommandParameterInternal[][] pipeElements,
CommandBaseAst[]
pipeElementAsts, CommandRedirection[][] commandRedirections,
FunctionContext funcContext)
at
System.Management.Automation.Interpreter.ActionCallInstruction`6.Run(InterpretedFrame
frame)
at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame
frame)
TargetObject :
Bad-Command
CategoryInfo :
ObjectNotFound: (Bad-Command:String) [], CommandNotFoundException
FullyQualifiedErrorId : CommandNotFoundException
ErrorDetails :
InvocationInfo :
System.Management.Automation.InvocationInfo
ScriptStackTrace :
at , : line 1
PipelineIterationInfo : {}
You can see that our error object has a property called Exception. When I expand this property and pipe it to Get-Member, you can see that it is an
object itself.
TypeName:
System.Management.Automation.CommandNotFoundException
Name
MemberType Definition
----
---------- ----------
Equals
Method bool
Equals(System.Object obj), bool _Exception.Equals(System.Object obj)
GetBaseException
Method System.Exception
GetBaseException(), System.Exception _Exception.GetBaseException()
GetHashCode
Method int GetHashCode(), int
_Exception.GetHashCode()
GetObjectData
Method void
GetObjectData(System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context), void ISerial...
GetType
Method type GetType(), type _Exception.GetType()
ToString
Method string ToString(),
string _Exception.ToString()
CommandName
Property string CommandName
{get;set;}
Data
Property
System.Collections.IDictionary Data {get;}
ErrorRecord
Property
System.Management.Automation.ErrorRecord ErrorRecord {get;}
HelpLink
Property string HelpLink
{get;set;}
HResult
Property int HResult
{get;set;}
InnerException
Property System.Exception
InnerException {get;}
Message
Property string Message
{get;}
Source
Property string Source
{get;set;}
StackTrace
Property string StackTrace
{get;}
TargetSite
Property
System.Reflection.MethodBase TargetSite {get;}
WasThrownFromThrowStatement Property bool WasThrownFromThrowStatement {get;set;}
Only an XML file can handle multidimensional data. The problem with the Export-CliXML cmdlet is that it does not have the capability to
append to itself. That is just the way
XML is.
Comments