PowerShell

Sending information to Event Log with extended fields using PowerShell

Reading Event Logs is something that every admin does or at least should do quite often. When writing PowerShell scripts, you often need to read event logs to find out different things across your infrastructure. But now and then it's quite the opposite. You need to write something to Event Log so it can be recorded for the future. Sure, you can write your information to log files, but since Windows already has a built-in logging system, it may be much easier to write stuff to event log. This allows you to centralize your event logs and processed by specialized tools like SIEM.

Writing to Event Log with standard PowerShell commands

As you may be aware, PowerShell allows you to send useful information to Event Logs providing similar ability as other applications. It's all straightforward using the Write-EventLog command.

Write-EventLog -LogName "Application" -Source "MyApp" -EventID 3001 -EntryType Information -Message "MyApp added a user-requested feature to the display." -Category 1 -RawData 10,20

Or something similar to this one

Write-EventLog -LogName Application -Source "MySpecialApp" -EventID 3001 -Message "MyApp added a user-requested feature to the display."

Of course, you need first to create Source for MyApp otherwise if you try to run code above you will get an error

Write-EventLog : The source was not found, but some or all event logs could not be searched. Inaccessible logs: Security.
At line:1 char:1
+ Write-EventLog -LogName Application -Source “MySpecialApp” -EventID 3 …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-EventLog], SecurityException
+ FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShell.Commands.WriteEventLogCommand

As a standard user, you don't have access to the Security log. Therefore the error can be a bit misleading. It just states that the Source cannot be found, but at the same time points to problems with reading Security log. However, even with Administrative rights, the error doesn't go away

Write-EventLog : The source name “MySpecialApp” does not exist on computer “localhost”.
At line:1 char:1
+ Write-EventLog -LogName Application -Source “MySpecialApp” -EventID 3 …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Write-EventLog], InvalidOperationException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteEventLogCommand

This error happens because before you can send something to the event log, you need to create a Source for it. Event log needs to distinguish different sources so that when you search for it in the future, it's much simpler to find. This gives you a way to identify logs sent from one script from another. This is done with the following command

New-EventLog -LogName 'Application' -Source 'MySpecialApp' -ErrorAction Stop

Keep in mind that for that you will need administrative access to your machine.

Reading Additional Fields from Event Log

But this is not what I wanted to talk about. You see, when you use the Write-EventLog method, you can define Message, Category, and EntryType (which is Level in the output below), and nothing more.

But what if you are sending a lot more data into a message? Additional fields that, when reading the event log, would be useful in the form of other fields?

All that additional data is written on the XML level

Write-EventLog can't do that! It can only write Message value. However, if one would like to get individual values from that event log, it would require some heavy text parsing. I can hear you saying that this additional data is not easily accessible anyways, and you would be partially right. With Get-WinEvent or Get-EventLog, there are two ways to do it. However, since I have already spent a lot of time on something I've not planned for this article, let me send you to source where you can read more about it – PowerShell – Everything you wanted to know about Event Logs and then some. My solution to this problem is my PSEventViewer PowerShell module which extracts those hidden fields with zero effort (among other things).

Get-Events -LogName 'Application' -ProviderName 'Windows Error Reporting' -ID 1001 -Level Informational -MaxEvents 1

This means that we can use the Get-Events command and get NoNameA5 property and find out TeamViewer.exe was the application affected in this particular event. But just because it's called NoName, in this case, doesn't mean it's always the case. Depending on the type of event you're parsing, sometimes those fields will be named fields. Get-Events can deliver you the full output that's stored in the XML.

Using Write-Event from PSEventViewer to create events with additional fields

Ok, so we know how to read that data, we know that Write-EventLog doesn't provide that functionality, so how can we do it ourselves? Glad you ask! Well, I've written this little PowerShell command and included it in the PSEventViewer module.

Write-Event -LogName 'Application' -EntryType Information -ID 1000 -Source 'MySuperSexyApp' -AdditionalFields 'Add me', 'And me' -Message 'This is very long message that includes: addme, and me'

As you can see above, we used Write-Event function, and by using the Message parameter and AdditionalFields parameter (which takes an Array of strings), we sent additional fields to XML. We can quickly verify how it looks with Get-Events function

Get-Events -LogName 'Application' -ID 1000 -ProviderName 'MySuperSexyApp' | fl *

If you think this article was interesting, and you have 60 more minutes to spend, you may also find PowerShell – Everything you wanted to know about Event Logs and then some useful. It covers details of reading Event Logs with PowerShell with both standard ways in PowerShell (Get-WinEvent / Get-EventLog) but also includes what Get-Events can do. And it can do a lot!

PSEventViewer Details

While you can use the script in a standard way by downloading it from GitHub, putting it in right places and getting it to run…there is much simpler way. Since the script was published to PowerShell Gallery you can simply install the module and run it from anywhere. Just use Install-Module PSEventViewer.

Install-Module -Name PSEventViewer 

If you ever need to update it…

Update-Module -Name PSEventViewer 
Issues should be reported on GitHub
Code is published on GitHub
Code is published as a module on PowerShellGallery

For details on code, in case of any issues, please report them on GitHub.

Przemyslaw Klys

System Architect with over 14 years of experience in the IT field. Skilled, among others, in Active Directory, Microsoft Exchange and Office 365. Profoundly interested in PowerShell. Software geek.

Share
Published by
Przemyslaw Klys

Recent Posts

Upgrade Azure Active Directory Connect fails with unexpected error

Today, I made the decision to upgrade my test environment and update the version of…

6 days ago

Mastering Active Directory Hygiene: Automating Stale Computer Cleanup with CleanupMonster

Have you ever looked at your Active Directory and wondered, "Why do I still have…

4 months ago

Active Directory Replication Summary to your Email or Microsoft Teams

Active Directory replication is a critical process that ensures the consistent and up-to-date state of…

8 months ago

Syncing Global Address List (GAL) to personal contacts and between Office 365 tenants with PowerShell

Hey there! Today, I wanted to introduce you to one of the small but excellent…

1 year ago

Active Directory Health Check using Microsoft Entra Connect Health Service

Active Directory (AD) is crucial in managing identities and resources within an organization. Ensuring its…

1 year ago

Seamless HTML Report Creation: Harness the Power of Markdown with PSWriteHTML PowerShell Module

In today's digital age, the ability to create compelling and informative HTML reports and documents…

1 year ago