Back to script library
Entra / Microsoft 365 · Compliance & audit

Find MailItemsAccessed audit records

Process Microsoft 365 MailItemsAccessed unified audit log records and format them into a more digestible report.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Connect-ExchangeOnline

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

param(
[int] $LookbackDays = 10
)
Clear-Host
$Now = Get-Date
Write-Host "Finding MailItemsAccessed records..."
$SearchStartDate = (Get-Date).AddDays(-$LookbackDays) #For Message Trace
$SearchEndDate = (Get-Date).AddDays(+1)
# Edit this line to use whatever search terms you wnat to find audit records
[array]$Records = (Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-$LookbackDays) -EndDate $SearchEndDate -Operations MailItemsAccessed -SessionCommand ReturnLargeSet -ResultSize 5000)
If ($Records.Count -eq 0) {
Write-Host "No audit records for mail access found."
Break
}
Clear-Host
# Remove any duplicates
$Records = $Records | Sort-Object Identity -Unique
$ProgressDelta = 100/($Records.count); $PercentComplete = 0; $RecordNumber = 0;
Write-Host "Processing" $Records.Count "MailItemsAccessed audit records..."
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file
# Scan each audit record to extract information
ForEach ($Rec in $Records) {
$RecordNumber++
$AuditData = ConvertFrom-Json $Rec.Auditdata
$TimeStamp = Get-Date($AuditData.CreationTime) -format 'dd-MMM-yyyy HH:mm:ss'
Write-Output ("Checking audit record {0}" -f $RecordNumber)
Switch ($AuditData.LogonType) { #Easier to read than to remember logon type codes
"0" {$LogonType = "User"}
"1" {$LogonType = "Admin"}
"2" {$LogonType = "Delegate"}
} # End Switch
$RecordType = $Auditdata.OperationProperties | Where-Object {$_.Name -eq "MailAccessType"}
$DaysSince = New-TimeSpan(Get-Date($AuditData.CreationTime))
$i = 0
Switch ($RecordType.Value) { #Figure out the folder names and extract message information for Bind events
"Bind" { $FolderId = $AuditData.Folders.Id; $Folder = $AuditData.Folders.Path.Split("\")[1]
ForEach ($Msg in $Auditdata.Folders.FolderItems) {
$i++; $Subject = $Null
# Section to try and find the message subject using a message trace
$MsgId = $Msg.InternetMessageId.Substring(1, ($Msg.InternetMessageId.Length -2)) #Trim the message identifier
If ($DaysSince.Days -le 10) { # Within the last 10 days so try a message trace
$Subject = (Get-MessageTrace -MessageId $MsgId -StartDate $SearchStartDate -EndDate $SearchEndDate)
If ($Null -ne $Subject) {$Subject = $Subject[0].Subject } #If we get a subject, take the first because a trace might return multiple results
} # Not worth tracing because it's too far back
Else
{ $Subject = "Too far back to trace" } # Find message subject
If ($Subject -eq $Null) { $Subject = "***** No trace data available ******" } # catch all
If ($i -eq 1) { $Messages = "(" + $i + ") " + $MsgId + " (" + $Subject + ")" } # Format output
Else { $Messages = $Messages + "; (" + $i + ") " + $MsgId + " (" + $Subject + ")" }
} #End Foreach
} #End of Bind-specific processing
"Sync" { $FolderId = $AuditData.Item.Id; $Folder = $AuditData.Item.Parentfolder.Name
$Messages = $Null }
} #End Switch
$Throttled = $Null
$Throttled = $Auditdata.OperationProperties |Where-Object {$_.Name -eq "IsThrottled"}
$ReportLine = [PSCustomObject] @{
TimeStamp = $TimeStamp
Mailbox = $AuditData.MailboxOwnerUPN
User = $AuditData.UserId
LogonType = $LogonType
FolderId = $FolderId
Folder = $Folder
Access = $RecordType.Value
Operation = $RecordType.Name
Throttled = $Throttled.Value
ClientIP = $AuditData.ClientIPAddress
ClientInfo = $AuditData.ClientInfoString
SessionId = $AuditData.SessionId
Operations = $AuditData.OperationCount
Messages = $Messages }
$Report.Add($ReportLine)
}
$Report | Sort-Object {$_.TimeStamp -as [DateTime]} | Out-GridView
$Report | Sort-Object {$_.TimeStamp -as [DateTime]} | Export-CSV -NoTypeInformation c:\temp\MailItemsAccessed.csv

Parameters

ParameterDefaultNotes
-LookbackDays10Number of days back to search MailItemsAccessed audit records.
Attribution