Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Better Event Logs with PowerShell

Posted on January 24, 2020April 21, 2021

Because I don't work in a corporate environment, I don't always see opportunities where PowerShell can make your life better as an IT professional. I have a friend -- let's call her Gladys Kravitz. Gladys and I were chatting and she mentioned how tricky it is to pull information out of Windows event logs. If I recall, she was looking at 4625 events in the Security log which represents failed logon attempts. Here's an example:

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!
A failed logon attempt

Reading the message it is clear that user Aprils in the Company domain tried to logon to Win10. But how would you get that information from event logs on 100 of machines? You could resort to some regular expression voodoo to extract the information. The values are actually part of the event log record. You may have seen ReplacementStrings when using Get-Eventlog. When using Get-WinEvent these values are stored as properties.

Event entry properties

Assuming these values were consistent, you could write a function to create a custom object from these values. But I'm always thinking of the bigger picture. What Gladys really wanted is a way to turn the event log record into a structured object she could use in PowerShell. This issue with replacement strings goes beyond this particular situation.

XML to the Rescue

You probably don't think of XML as a solution, but in this case, it XML saves the day. The event log record object you get from Get-WinEvent includes a method to create an XML version.

 $r = get-winevent -FilterHashtable @{Logname="Security";ID=4625} -MaxEvents 1 -ComputerName Win10 [xml]$evt = $r.ToXml() 

This document has properties that expose the data used to construct the event log record.

Parsing the XML document

The Data node looks promising.

Event entry data

That almost looks like an object! I'll make one.

$evt.Event.EventData.Data | foreach-object -Begin {$h = @{}} -Process {
 $h.add($_.name,$_.'#text')
} -end { $obj = New-Object -TypeName PSObject -Property $h }
A strructured object from event log data

I can build a tool around this to convert event log records into more meaningful objects. And that's exactly what I did for Gladys.

Convert-EventLogRecord

I wrote a function called Convert-EventLogRecord that is part of the latest release of my PSScriptTools module. The function is designed to convert event log entries into custom objects. The function creates a custom object with the data properties I showed, but other information as well such as event id, log name and computername.

A converted event

Now Gladys has a PowerShell tool to get the information she wants in the form she wants.

An event log report

This isn't a perfect tool. Some even log entries don't have extra data. Or the data they have is just a list of strings. In those cases, the data is stored as RawProperties.

Raw event data properties

But once I know that I can write a control script or other tooling.

Tooling with Convert-EventLogRecord

As you explore different events in different logs you figure out what things look like. Sometimes the event log data isn't helpful. But with a little PowerShell effort on your part, you can create meaningful results. You should be able to run this code on your desktop.

Get-WinEvent -FilterHashtable @{Logname ='system';ID =7040} -MaxEvent 50 |
Convert-EventlogRecord | 
Sort-Object -Property Param4,TimeCreated -Descending |
Format-Table -GroupBy @{Name="Service";Expression={$_.param4}} -Property TimeCreated,
@{Name="OriginalState";Expression = {$_.param2}},
@{Name="NewState";Expression={$_.param3}},Computername

The results show you when services changed state.

Changed service state event logs

I've been showing results as formatted tables. But you can do whatever you want because the Convert-EventLogRecord function is writing an object to the pipeline. Run whatever Get-Winevent query or command you want, convert the results, and then do what you need to with the results.

I gave the code to Gladys to try out but now you can get it as well in the PSScriptTools module, beginning with version 2.13. I hope you'll give it a try and let me know what you think.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

3 thoughts on “Better Event Logs with PowerShell”

  1. Nolan says:
    January 30, 2020 at 6:26 pm

    I have a very similar function to this. The one thing I’m left wanting is a way to replace all the placeholders with their insertion strings. Here’s a summary of the issue that I had written up before. >>>>Values like “%%2307” (or with only a single leading “%”) are insertion string placeholders. Messages are formed from message text files, which typically are compiled as .DLLs but can also be included in .EXEs (and maybe other) resources. The location of these message text files is stored in the registry under subkeys of HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog, that corresponds with the specific logname and source. So essentially you have have something like HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\EventLog\\. Once you locate the correct key, the location data is stored in a value named EventMessageFile, which points to the path of the .DLL (or other type of file). There can also be a value for CategoryMessageFile, and ParameterMessageFile (these could all point to the same file, or different ones). As I understand it, the ParameterMessageFile is where the insertion strings are defined for the placeholders which begin with a double percent sign (%%xxxx).

    So far I haven’t found any way to parse a message text file for insertion strings which correspond to their numbers.

    The only bright side is that the message property of an event has already gone through the process of formatting (probably through the use of the FormatMessage function – https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-formatmessage), substituting all the placeholders with their insertion strings corresponding with the proper language.<<<<<<<
    Care to take up the challenge?

    1. Stuart says:
      April 13, 2020 at 1:02 pm

      Hi Nolan,

      Have a look at this: https://github.com/wightsci/MessageTableReader – it’s a .Net class I put together to read the substitution strings from a .dll . You can use it within a PowerShell module or script, or compile it into a .dll .

      Stuart

      1. Nolan says:
        June 26, 2020 at 8:18 pm

        Stuart,
        Thank you so much! I just remembered to check again whether I had received any replies (never got an email notification) and found your comment. I spent a few minutes experimenting with your code and I like what I see. I’m going to have spend some time to integrate that .Net class into my PS function.
        I might try modifying it so that GetMessageList() (or another method) returns a hashtable. I have a semi-idea of using that as a cached lookup table, though I’ve yet to do any performance testing with your class as-is.
        Again, many thanks for your contribution. I hope I can find the time to check out your eBook as well.
        Nolan

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d