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

Find deleted email audit records

Search the unified audit log to find who deleted messages via HardDelete and SoftDelete operations; output can be filtered to specific mailboxes.

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 = 90,
[string] $StartDate = (Get-Date).AddDays(-$LookbackDays); $EndDate = (Get-Date),
[string] $EndDate = (Get-Date)
)
If ($Null -eq (Get-ConnectionInformation)) {
Connect-ExchangeOnline
}
$Records = (Search-UnifiedAuditLog -StartDate $StartDate -EndDate $EndDate -Operations "HardDelete", "SoftDelete" -ResultSize 5000)
If (!($Records)) { Write-Host "No deletion records found."; break }
Else {
Write-Host "Processing" $Records.Count "audit records..."
$Report = [System.Collections.Generic.List[Object]]::new() # Create output file
ForEach ($Rec in $Records) {
$AuditData = ConvertFrom-Json $Rec.Auditdata
If ($AuditData.ResultStatus -eq "PartiallySucceeded") {
$EMailSubjects = "*** Not deleted by" + $AuditData.ClientInfoString + " ***" }
Else {
$EmailSubjects = $AuditData.AffectedItems.Subject -join ", " }
$ReportLine = [PSCustomObject] @{
TimeStamp = Get-Date($AuditData.CreationTime) -format g
User = $AuditData.UserId
Action = $AuditData.Operation
Status = $AuditData.ResultStatus
Mailbox = $AuditData.MailboxOwnerUPN
"Message Subjects" = $EmailSubjects
Folder = $AuditData.Folder.Path.Split("\")[1]
Client = $AuditData.ClientInfoString }
$Report.Add($ReportLine) }
}
$Report | Sort-Object Mailbox | Select Timestamp, Action, User, Mailbox, "Message Subjects", Folder | Out-GridView

Parameters

ParameterDefaultNotes
-LookbackDays90Number of days back to search deletion audit records.
-StartDate(Get-Date).AddDays(-90)Start of the audit log search window.
-EndDate(Get-Date)End of the audit log search window.
Attribution