Using the Audit Log to Generate a Daily Action Summary for a User
Analyze the Audit Events for a User Over a Single Day
I’m speaking about decoding the Microsoft 365 audit log at the ESPC conference in Stockholm, Sweden today. As part of the preparation for the session, I wanted to create a demo to highlight some of the challenges of interpreting audit records to attendees. I have many examples of PowerShell scripts that perform different tasks, like finding the last accessed date for documents stored in SharePoint Online. These scripts work well and solve problems, but they don’t shine a light onto the biggest single issue with audit log data. That issue is the maddening inconsistency found in the audit data payload contained in audit records.
The Two Parts of Audit Log Records
Audit records have two parts. The first is a consistent set of properties that must be respected by workloads when they generate audit records. These properties include the unique identity (GUID) for the record, a timestamp, the name of the user or process who performed an action, and the name of the action. The second part is the audit payload, a JSON structure contained in the AuditData property. Microsoft 365 workloads like Exchange Online and SharePoint Online control what they insert into the audit payload for their events, and no consistency and sometimes no reason governs what turns up in audit payloads.
The lack of consistency means that anyone attempting to interpret audit data must figure out what the audit payload contains and put it into context with what you know about the action captured by the event. The content differs from Exchange Online to SharePoint Online to Teams to Planner to Entra ID. The lack of consistency and the obvious errors in audit data points to poor control and attention to detail by engineering groups, both the team responsible for the audit log and the teams responsible for generating workload events.
Investigating User Actions for a Day
To illustrate the problem, I decided to create a script to report details of all actions taken by an individual user over a single day. I developed the script by fetching the audit records (about 2,200) logged for me on 27 November 2024 and reporting what I found. I stripped UserLoggedIn events from the set because of the number (946) of sign-ins to different applications from multiple devices. Most of the sign-ins are silent and result from the renewal of an access token. Figure 1 shows what the output report looks like.
The set of actions spanned interactions with multiple workloads for user activities like creating and updating documents, sending messages via Exchange and Teams, and reading a Planner task list. It also included some administrative actions like conducting an eDiscovery search, running some Exchange PowerShell cmdlets, and so on. No set of audit events for any single user will be 100% representative of what you’ll find across Microsoft 365, but I am confident that the results found in this set of audit records demonstrates the problem.
The script unpacks the audit payload for each event to extract a small set of properties for the report. A large Switch statement is used to interpret each type of event. It would be practically impossible to include every possible event, so I concentrated on common events and some that illustrate the problem.
In some cases, some of the properties contained in compliance audit records are obscured through Base64 encoding. Unfortunately, the encoding is resistant to PowerShell decoding unless you remove spurious characters at the end of the string. For example, here’s how the script handles events for the Get-ComplianceSearch action (retrieve details of a content search):
"Get-ComplianceSearch" { $Action = 'Compliance search retrieved' If ($AuditData.Parameters -eq '-ResultSize "Unlimited"' ) { $Object = "All results" } Else { $Object = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String( $AuditData.Parameters.Split('"')[1].SubString(0,32))) } $Location = $AuditData.Workload $Workload = 'eDiscovery' }
Some audit events contain details for multiple events. This is done for very good reason as the actions being captured are very common and would otherwise flood the audit log with data. The MailItemsAccessed event is a good example. This event is now available to Purview Audit Standard (Office 365 E3) customers and captures details of email items accessed by a user. The audit payload for a MailItemsAccessed event can contain details of 20 or 30 messages. MailItemsAccessed events can also contain details of sync actions (see this article and the associated script for details).
You can download the script to generate a report of user audit events for a day from GitHub. It’s easy to add processing for other events if you wish.
Consistency Would Make Administration Easier
The bottom line is that interpreting audit events takes a lot of knowledge and persistence. Like anything else in technology, the combination brings you a long way. It’s regrettable that Microsoft has allowed a situation to develop where nearly 2,000-odd audit events might need different processing to extract real value. Life would be so much easier if audit data was more consistent.
Insight like this doesn’t come easily. You’ve got to know the technology and understand how to look behind the scenes. Benefit from the knowledge and experience of the Office 365 for IT Pros team by subscribing to the best eBook covering Office 365 and the wider Microsoft 365 ecosystem.