Exchange Admin Audit Log with MgGraph

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

Exchange Logo

PowerShell Logo

Security Logo