PS: Logging

3 minute read

Description:

Logging is essential for anyone who is into scripting. In this post, I will assume you are using my Template script. I will just go over a couple things.

To Resolve:

  1. First, there are multiple ways to log during your script:

    # Writes whatever is stored in $Message to the screen, to the Windows Event Log, and to the log file.
    Write-Gwlog "$Message" -Color Cyan
    
    # Write the word "Output" to the screen, to the Windows Event Log, and to the log file.
    Log "Output"
    
    # Write the whatever is stored in $Message to the screen in dark red, to the Windows Event Log as an error, and to the log file.
    Write-Gwlog "$Message" -Color DarkRed -Error
    
    • Pretty simple stuff, this right here is the main point of my -Log functions. But let’s do some more stuff…
  2. You may have noticed the following that I place at the top of my Process block:

    # This will capture any errors in the script and place them in the Event Log and the log file.
    
    Trap
    {
    Write-EventLog –Message $($_.Exception.Message) –LogName Application –Source $Logfile –EntryType Error –EventID 40 -Category 0
    ((Get-Date -Format "yyyy-MM-dd hh:mm:ss tt") + ": " + $($_.Exception.Message)) | Out-File -FilePath $Logfile -Append
    }
    
    • To test, just write the following underneath it and then run your script:
    SomethingWentWrong  
    SomethingWentWrongAgain  
    ThingsJustKeepGoingWrong!
    
  3. So the Event Viewer doesn’t store variables as well as logging does so you have to be creative when you log. For example:

    $A = Get-Process
    
    # Event viewer shows this garbage:
    Processes: System.Diagnostics.Process (AdjustService) System.Diagnostics.Process (ApplicationFrameHost) System.Diagnostics.Process (audiodg) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (chrome) System.Diagnostics.Process (conhost) System.Diagnostics.Process (csrss) System.Diagnostics.Process (csrss) System.Diagnostics.Process (cvpnd) System.Diagnostics.Process (dasHost) System.Diagnostics.Process (dllhost) System.Diagnostics.Process (dwm) System.Diagnostics.Process (explorer) System.Diagnostics.Process (explorer) System.Diagnostics.Process (fontdrvhost) System.Diagnostics.Process (fontdrvhost) System.Diagnostics.Process (GfExperienceService) System.Diagnostics.Process (GoogleCrashHandler) System.Diagnostics.Process (GoogleCrashHandler64) System.Diagnostics.Process (googledrivesync) System.Diagnostics.Process (googledrivesync) System.Diagnostics.Process (Greenshot) System.Diagnostics.Process (HeciServer) System.Diagnostics.Process (Idle) System.Diagnostics.Process (igfxCUIService) System.Diagnostics.Process (igfxEM) System.Diagnostics.Process (Jhi_service) System.Diagnostics.Process (LMI_Rescue_srv) System.Diagnostics.Process (LMIGuardianSvc) System.Diagnostics.Process (lsass)
    
    • If you just want to store a variable such as $A = Get-Process, you can just type:
    Log "Processes: $a"
    
    • But if you want to access a property of the process like $a.processname, you have to surround it in parenthesis and place an outside dollar sign:
    Log "Processes: $($a.processname)"
    
    • So now we get this:
    Processes: AdjustService ApplicationFrameHost audiodg chrome chrome chrome chrome chrome chrome chrome chrome chrome chrome chrome conhost csrss csrss cvpnd dasHost dllhost dwm explorer explorer fontdrvhost fontdrvhost GfExperienceService GoogleCrashHandler GoogleCrashHandler64 googledrivesync googledrivesync Greenshot HeciServer Idle igfxCUIService igfxEM Jhi_service LMI_Rescue_srv LMIGuardianSvc lsass MediaMonkey Memory Compression mqsvc MSASCuiL MsMpEng NisSrv notepad++ notepad++ NvBackend NVDisplay.Container NVDisplay.Container NvNetworkService nvtray OfficeClickToRun ONENOTE PnkBstrA powershell powershell_ise PresentationFontCache qc RAVCpl64 RuntimeBroker SearchFilterHost SearchIndexer SearchProtocolHost SearchUI SecurityHealthService services ShellExperienceHost sihost smartscreen smss SMSvcHost SMSvcHost spoolsv sqlservr sqlwriter Steam SteamService steamwebhelper
    
    • So now that we get the Event Viewer logging all of our processes, but why are they all on one line? Well we have to add a new line to each output process:
    Log "These are your processes: `n$($a -Join [Environment]::Newline)" -Color Yellow
    
    # Notice the lack of a space after `n. Also if you want to access a property, follow 3b, so:
    
    Log "These are your processes: `n$($($a.processname) -Join [Environment]::Newline)" -Color Yellow
    
    # Now it looks right:
    
    These are your processes:
    AdjustService
    ApplicationFrameHost
    audiodg
    chrome
    chrome
    chrome
    chrome
    chrome
    
    • The last thing to touch on is tables. The log file will store these fine, but once again the Event Viewer will need some extra work. I find myself using Out-String quite a bit:
    $C = Get-Culture | Select-Object *
    
    $D = Out-String -Inputobject $C -Width 100
    
    Write-Gwlog "$D"
    
    # or:
    
    $F = Out-String -Inputobject (Get-Culture)
    
    Write-Gwlog "$F"
    
  4. If you have specific commands that you want to test for errors, try:

    Try
    {
    Do-Something -Erroraction Stop
    }
    Catch
    {
    Write-Gwlog $($_.Exception.Message) -Color Darkred -Error
    }