Exchange Admin Audit Log with MgGraph
Hi All,
A few Weeks ago, i’ve written an Article about Exchange Admin Audit Log using the Graph AuditLog Querys with Invoke-MgGraphRequest. I’ve rewritten the code to the MgGraph commandlet’s in this Article.
PowerShell Code with MgGraph
We need to have an Entra Application with the following Permissions:
- AuditLog.Read.All
- AuditLogsQuery.Read.Al
###############################################################################
# Variables
###############################################################################
$TenantId = "46bbad84-29f0-4e03-8d34-f6841a5071ad" #Icewolf
$AppID = "99d8df8d-67b6-4a3a-b915-5cfc835fbfc7" #AuditLog
$CertificateThumbprint = "FB40D47A0C0A23EA297B44A57272BCED352D0002" #O365Powershell5
$OutputFile = "C:\Temp\GraphAuditLog.json"
Connect-MgGraph -ClientId $AppID -TenantId $TenantId -CertificateThumbprint $CertificateThumbprint -NoWelcome
###############################################################################
# Create Search
###############################################################################
Write-Output "Create Search"
$DisplayName = "DemoSearch_" + (Get-Date -Format "yyyyMMdd_HHmm")
# First day of previous month
[DateTime]$StartDate = (Get-Date -Day 1).AddMonths(-1).Date
# First day of current month
# Using this is preferable to 23:59:59 on the last day
[DateTime]$EndDate = (Get-Date -Day 1).Date
$SearchParameters = @{
DisplayName = $DisplayName
FilterStartDateTime = $StartDate
FilterEndDateTime = $EndDate
RecordTypeFilters = @("ExchangeAdmin")
OperationFilters = @(
"Add-MailboxPermission"
"Remove-MailboxPermission"
"Add-RecipientPermission"
"Remove-RecipientPermission"
)
}
Write-Output "Create AuditLog Search"
$SearchQuery = New-MgSecurityAuditLogQuery @SearchParameters
$SearchId = $SearchQuery.Id
Write-Output "SearchId: $SearchId"
if ([string]::IsNullOrWhiteSpace($SearchId)) {
Write-Output "No SearchId > Aborting Script"
exit
}
###############################################################################
# Check if SearchQuery Succeeded
###############################################################################
Write-Output "Wait for Search to complete"
do
{
$AuditSearch = Get-MgSecurityAuditLogQuery -AuditLogQueryId $SearchId
$AuditSearchStatus = $AuditSearch.Status
Write-Output "Status: $AuditSearchStatus"
if ($AuditSearchStatus -eq "failed")
{
Write-Output "Audit Search failed - aborting Script"
exit
}
if ($AuditSearchStatus -ne "succeeded")
{
Start-Sleep -Seconds 60
}
}
while ($AuditSearchStatus -ne "succeeded")
###############################################################################
# Get Data from SearchQuery
###############################################################################
Write-Output "Get audit records"
[array]$AuditRecords = Get-MgSecurityAuditLogQueryRecord -AuditLogQueryId $SearchId -All
$AuditRecordCount = $AuditRecords.Count
Write-Output "Audit Records found: $AuditRecordCount"
Let’s have a look at the AuditRecord Entry. The AccessRight is in the AuditData.AdditionalProperties.Parameters Property
$AuditRecords[0] | fl
$AuditRecords[0].AuditData.AdditionalProperties
$AuditRecords[0].AuditData.AdditionalProperties.Parameters
Now we can filter the Output
###############################################################################
# Filter Output
###############################################################################
$AuditRecords |
Select-Object @{
Name = 'CreationTime'
Expression = { $_.AuditData.AdditionalProperties['CreationTime'] }
},
@{
Name = 'UserKey'
Expression = { $_.AuditData.AdditionalProperties['UserKey'] }
},
UserId,
ObjectId,
Operation,
@{
Name = 'AccessRights'
Expression = {
(
$_.AuditData.AdditionalProperties['Parameters'] |
Where-Object { $_['Name'] -eq 'AccessRights' }
)['Value']
}
} |
ConvertTo-Json -Depth 5 |
Set-Content -Path $OutputFile
Regards
Andres Bohren





