Skip to main content

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. 

Comments

Popular posts from this blog

Adding a Comment to a GPO with PowerShell

As I'm writing this article, I'm also writing a customization for a PowerShell course I'm teaching next week in Phoenix.  This customization deals with Group Policy and PowerShell.  For those of you who attend my classes may already know this, but I sit their and try to ask the questions to myself that others may ask as I present the material.  I finished up my customization a few hours ago and then I realized that I did not add in how to put a comment on a GPO.  This is a feature that many Group Policy Administrators may not be aware of. This past summer I attended a presentation at TechEd on Group Policy.  One organization in the crowd had over 5,000 Group Policies.  In an environment like that, the comment section can be priceless.  I always like to write in the comment section why I created the policy so I know its purpose next week after I've completed 50 other tasks and can't remember what I did 5 minutes ago. In the Group Policy module for PowerShell V3, th

Return duplicate values from a collection with PowerShell

If you have a collection of objects and you want to remove any duplicate items, it is fairly simple. # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   # Remove the duplicate values. $Set1 | Select-Object -Unique 1 2 3 4 5 6 7 What if you want only the duplicate values and nothing else? # Create a collection with duplicate values $Set1 = 1 , 1 , 2 , 2 , 3 , 4 , 5 , 6 , 7 , 1 , 2   #Create a second collection with duplicate values removed. $Set2 = $Set1 | Select-Object -Unique   # Return only the duplicate values. ( Compare-Object -ReferenceObject $Set2 -DifferenceObject $Set1 ) . InputObject | Select-Object – Unique 1 2 This works with objects as well as numbers.  The first command creates a collection with 2 duplicates of both 1 and 2.   The second command creates another collection with the duplicates filtered out.  The Compare-Object cmdlet will first find items that are diffe

How to list all the AD LDS instances on a server

AD LDS allows you to provide directory services to applications that are free of the confines of Active Directory.  To list all the AD LDS instances on a server, follow this procedure: Log into the server in question Open a command prompt. Type dsdbutil and press Enter Type List Instances and press Enter . You will receive a list of the instance name, both the LDAP and SSL port numbers, the location of the database, and its status.