Audit Logs¶
The Microsoft 365 Unified Audit Log captures activity across Exchange Online, SharePoint Online, OneDrive, Teams, Entra ID, and other services.
Purview portal → Audit
Enable Audit Logging¶
Audit logging should be on by default for new tenants, but verify:
Connect-ExchangeOnline -UserPrincipalName admin@domain.com
# Check if audit is enabled
Get-AdminAuditLogConfig | Select-Object UnifiedAuditLogIngestionEnabled
# Enable if not already on
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true
Audit Log Retention¶
Default retention varies by licence:
| Licence | Default retention |
|---|---|
| Microsoft 365 E3 / Business Premium | 90 days |
| Microsoft 365 E5 / Advanced Audit | 1 year |
| Advanced Audit add-on | Up to 10 years (with additional licence) |
Extended retention policy (Advanced Audit — E5)¶
Purview portal → Audit → Audit retention policies → Create audit retention policy
| Setting | Value |
|---|---|
| Policy name | 1 Year — All Users All Activities |
| Record type | All |
| Duration | 1 year |
| Priority | 1 |
| Users | All users |
Searching the Audit Log¶
Via the portal¶
Purview portal → Audit → New search
| Field | Description |
|---|---|
| Date range | Up to 90 days per search (E3) or 1 year (E5) |
| Activities | Filter by specific activity types |
| Users | Search for specific user(s) |
| File/folder | Filter by resource name |
| IP address | Filter by source IP |
Common activities to search¶
| Activity category | What to look for |
|---|---|
| Azure AD sign-in | UserLoggedIn — failed logins, logins from new locations |
| Exchange | SendAs, HardDelete, MailboxLogin |
| SharePoint/OneDrive | FileDownloaded, FileSyncDownloadedFull, SharingInvitationCreated |
| Teams | MessageSent, TeamCreated, MemberAdded |
| DLP | DLPRuleMatch — policy matches |
| Azure AD | Add member to role, Delete user, Reset user password |
| Power Apps / Flow | Suspicious automation activity |
Searching via PowerShell¶
Connect-ExchangeOnline -UserPrincipalName admin@domain.com
# Search for all activity by a specific user in the last 7 days
$start = (Get-Date).AddDays(-7).ToString("MM/dd/yyyy HH:mm:ss")
$end = (Get-Date).ToString("MM/dd/yyyy HH:mm:ss")
Search-UnifiedAuditLog -StartDate $start -EndDate $end `
-UserIds "user@domain.com" -ResultSize 1000 |
Select-Object CreationDate, UserIds, Operations, AuditData |
Sort-Object CreationDate -Descending
# Search for all failed logins in the last 24 hours
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-1) -EndDate (Get-Date) `
-Operations "UserLoginFailed" -ResultSize 1000 |
ForEach-Object {
$data = $_.AuditData | ConvertFrom-Json
[PSCustomObject]@{
Time = $_.CreationDate
User = $data.UserId
IP = $data.ClientIP
UserAgent = $data.ExtendedProperties | Where-Object { $_.Name -eq "UserAgent" } | Select-Object -ExpandProperty Value
}
}
# Search for external file sharing events
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) `
-Operations "SharingInvitationCreated","AnonymousLinkCreated" -ResultSize 2000 |
ForEach-Object {
$data = $_.AuditData | ConvertFrom-Json
[PSCustomObject]@{
Time = $_.CreationDate
User = $data.UserId
TargetEmail = $data.TargetUserOrGroupName
File = $data.ObjectId
}
} | Where-Object { $_.TargetEmail -notlike "*@yourdomain.com" }
# Search for admin role changes
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) `
-Operations "Add member to role","Remove member from role" -ResultSize 500 |
ForEach-Object {
$data = $_.AuditData | ConvertFrom-Json
[PSCustomObject]@{
Time = $_.CreationDate
Actor = $data.UserId
Target = ($data.ModifiedProperties | Where-Object { $_.Name -eq "Role.WellKnownObjectName" }).NewValue
Action = $_.Operations
}
}
Alerting on Audit Events¶
Purview portal → Audit → Alert policies (or via Microsoft Defender portal)
Recommended alert policies:
| Alert | Trigger | Severity |
|---|---|---|
| Admin privilege escalation | Add member to Global Admin role | High |
| Mass file download | User downloads >500 files in 1 hour | High |
| Forwarding rule created | New inbox forwarding rule to external address | High |
| Multiple failed logins | >10 failed logins for a single user | Medium |
| Anonymous sharing link created | AnonymousLinkCreated | Medium |
| DLP policy match | DLPRuleMatch on high-severity policy | High |
| Malware detected in email | A malware campaign was detected | High |
Exporting Audit Logs¶
Export logs to CSV for long-term storage or SIEM ingestion:
# Export all audit logs for a date range to CSV
$results = Search-UnifiedAuditLog -StartDate "2025-01-01" -EndDate "2025-01-31" `
-ResultSize 5000
$results | Select-Object CreationDate, UserIds, Operations, `
@{N="AuditDataParsed";E={ $_.AuditData }} |
Export-Csv -Path ".\AuditLog-Jan2025.csv" -NoTypeInformation
# For large exports, loop through pages
$sessionId = [Guid]::NewGuid().ToString()
$allResults = @()
do {
$batch = Search-UnifiedAuditLog -StartDate "2025-01-01" -EndDate "2025-01-31" `
-ResultSize 5000 -SessionId $sessionId -SessionCommand ReturnLargeSet
$allResults += $batch
} while ($batch.Count -eq 5000)
$allResults | Export-Csv -Path ".\AuditLog-Full.csv" -NoTypeInformation
SIEM integration
For continuous audit log ingestion into a SIEM (Splunk, Microsoft Sentinel, etc.), use the Office 365 Management Activity API or the built-in Microsoft Sentinel — Office 365 connector.