Advanced Windows PowerShell Scripting Video Training

Advanced Windows PowerShell Scripting Video Training
Advanced Windows PowerShell Scripting Video Training

Monday, October 3, 2016

Creating an Error Log

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. 

No comments: