Skip to content

Commit

Permalink
Update Get-HawkUserMailBoxAuditing to migrate from deprecated Search-…
Browse files Browse the repository at this point in the history
…AuditLog and to use Search-UnifiedAuditLog
  • Loading branch information
jonnybottles committed Dec 10, 2024
1 parent 0fe454e commit 44b9aeb
Showing 1 changed file with 151 additions and 87 deletions.
238 changes: 151 additions & 87 deletions Hawk/functions/User/Get-HawkUserMailboxAuditing.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -2,110 +2,174 @@
<#
.SYNOPSIS
Gathers Mailbox Audit data if enabled for the user.
.DESCRIPTION
Check if mailbox auditing is enabled for the user.
If it is pulls the mailbox audit logs from the time period specified for the investigation.
Retrieves mailbox audit logs from Microsoft 365 Unified Audit Log, focusing on mailbox
content access and operations. This function replaces the deprecated Search-MailboxAuditLog
cmdlet with modern UAL-based auditing.
Migration Changes:
- Old: Used Search-MailboxAuditLog for direct mailbox audit log access
- New: Uses Search-UnifiedAuditLog with separate collection of:
* ExchangeItem records (item-level operations)
* ExchangeItemGroup records (access patterns)
The new implementation provides:
- Improved visibility into mailbox item access patterns
- More consistent data collection across Exchange Online
- Automatic pagination for large result sets
- Integration with Microsoft 365 compliance center
- Separated output files for better data analysis
Note: Administrative actions on mailboxes (like granting permissions) are tracked by
Get-HawkUserAdminAudit instead of this function.
Will pull from the Unified Audit Log and the Mailbox Audit Log
.PARAMETER UserPrincipalName
Single UPN of a user, commans seperated list of UPNs, or array of objects that contain UPNs.
.OUTPUTS
Single UPN of a user, comma-separated list of UPNs, or array of objects that contain UPNs.
File: Exchange_UAL_Audit.csv
.OUTPUTS
ExchangeItem Records:
File: ExchangeItem_Simple_{User}.csv/.json
Path: \<User>
Description: All Exchange related audit events found in the Unified Audit Log.
Description: Flattened item-level operations data in CSV and JSON formats
File: Exchange_Mailbox_Audit.csv
File: ExchangeItem_Logs_{User}.csv/.json
Path: \<User>
Description: All Exchange related audit events found in the Mailbox Audit Log.
.EXAMPLE
Get-HawkUserMailboxAuditing -UserPrincipalName [email protected]
Search for all Mailbox Audit logs from [email protected]
.EXAMPLE
Get-HawkUserMailboxAuditing -UserPrincipalName (get-mailbox -Filter {Customattribute1 -eq "C-level"})
Search for all Mailbox Audit logs for all users who have "C-Level" set in CustomAttribute1
#>

param
(
[Parameter(Mandatory = $true)]
[array]$UserPrincipalName
)

Function Get-MailboxAuditLogsFiveDaysAtATime {
param(
[Parameter(Mandatory = $true)]
[datetime]$StartDate,
[Parameter(Mandatory = $true)]
[datetime]$EndDate,
[Parameter(Mandatory = $true)]
$User
)


# Setup the initial start date
[datetime]$RangeStart = $StartDate

do {
# Get the end of the Range we are going to gather data for
[datetime] $RangeEnd = ($RangeStart.AddDays(5))
# Do the actual search
Out-LogFile ("Searching Range " + [string]$RangeStart + " To " + [string]$RangeEnd)
[array]$Results += Search-MailboxAuditLog -StartDate $RangeStart -EndDate $RangeEnd -identity $User -ShowDetails -ResultSize 250000

# Set the RangeStart = to the RangeEnd so we do the next range
$RangeStart = $RangeEnd
}
# While the start range is less than the end date we need to keep pulling in 5 day increments
while ($RangeStart -le $EndDate)
Description: Raw item-level operations data in CSV and JSON formats
# Return the results object
Return $Results

}

### MAIN ###
Test-EXOConnection
Send-AIEvent -Event "CmdRun"

# Verify our UPN input
[array]$UserArray = Test-UserObject -ToTest $UserPrincipalName
File: ExchangeItem_Raw.json
Path: \<User>
Description: Raw JSON dump of item operations audit data
foreach ($Object in $UserArray) {
[string]$User = $Object.UserPrincipalName
ExchangeItemGroup Records:
File: ExchangeItemGroup_Simple_{User}.csv/.json
Path: \<User>
Description: Flattened access pattern data in CSV and JSON formats
Out-LogFile ("Attempting to Gather Mailbox Audit logs " + $User) -action
File: ExchangeItemGroup_Logs_{User}.csv/.json
Path: \<User>
Description: Raw access pattern data in CSV and JSON formats
# Test if mailbox auditing is enabled
$mbx = Get-Mailbox -identity $User
if ($mbx.AuditEnabled -eq $true) {
# if enabled pull the mailbox auditing from the unified audit logs
Out-LogFile "Mailbox Auditing is enabled."
Out-LogFile "Searching Unified Audit Log for Exchange Related Events"
File: ExchangeItemGroup_Raw.json
Path: \<User>
Description: Raw JSON dump of access pattern audit data
$UnifiedAuditLogs = Get-AllUnifiedAuditLogEntry -UnifiedSearch ("Search-UnifiedAuditLog -UserIDs " + $User + " -RecordType ExchangeItem") | select-object -Expandproperty AuditData | convertfrom-json
Out-LogFile ("Found " + $UnifiedAuditLogs.Count + " Exchange audit records.")
.EXAMPLE
Get-HawkUserMailboxAuditing -UserPrincipalName [email protected]
# Output the data we found
$UnifiedAuditLogs | Out-MultipleFileType -FilePrefix "Exchange_UAL_Audit" -User $User -csv -json
Search for all Mailbox Audit logs from [email protected], creating separate files for
item operations and access patterns, each with both raw and processed formats.
# Search the MailboxAuditLogs as well since they may have different/more information
Out-LogFile "Searching Exchange Mailbox Audit Logs (this can take some time)"
.EXAMPLE
Get-HawkUserMailboxAuditing -UserPrincipalName (Get-Mailbox -Filter {CustomAttribute1 -eq "C-level"})
$MailboxAuditLogs = Get-MailboxAuditLogsFiveDaysAtATime -StartDate $Hawk.StartDate -EndDate $Hawk.EndDate -User $User
Out-LogFile ("Found " + $MailboxAuditLogs.Count + " Exchange Mailbox audit records.")
Search for all Mailbox Audit logs for all users who have "C-Level" set in CustomAttribute1,
creating separate output files for each user's item operations and access patterns.
# Output the data we found
$MailboxAuditLogs | Out-MultipleFileType -FilePrefix "Exchange_Mailbox_Audit" -User $User -csv -json
.NOTES
In older versions of Exchange Online, Search-MailboxAuditLog provided direct access to
mailbox audit data. This has been replaced by the Unified Audit Log which provides a
more comprehensive and consistent view of mailbox activities through separate record types:
- ExchangeItem: Tracks specific operations on items
- ExchangeItemGroup: Tracks access patterns and aggregated activity
Each record type is processed separately and output in multiple formats to support
different analysis needs:
- Simple (flattened) formats for easy analysis
- Raw formats for detailed investigation
- JSON dumps for programmatic processing
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[array]$UserPrincipalName
)

Test-EXOConnection
Send-AIEvent -Event "CmdRun"

# Verify our UPN input
[array]$UserArray = Test-UserObject -ToTest $UserPrincipalName

foreach ($Object in $UserArray) {
[string]$User = $Object.UserPrincipalName

Out-LogFile ("Attempting to Gather Mailbox Audit logs for: " + $User) -action

# Test if mailbox auditing is enabled
$mbx = Get-Mailbox -Identity $User
if ($mbx.AuditEnabled -eq $true) {
Out-LogFile "Mailbox Auditing is enabled."

try {
# Get the user's folder path
$UserFolder = Join-Path -Path $Hawk.FilePath -ChildPath $User
if (-not (Test-Path -Path $UserFolder)) {
New-Item -Path $UserFolder -ItemType Directory -Force | Out-Null
}

# Process ExchangeItem records
Out-LogFile "Searching Unified Audit Log for ExchangeItem events..."
$searchCommand = "Search-UnifiedAuditLog -UserIds $User -RecordType ExchangeItem"
$itemLogs = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand

if ($itemLogs.Count -gt 0) {
Out-LogFile ("Found " + $itemLogs.Count + " ExchangeItem events.")

# Write raw JSON dump
$RawJsonPath = Join-Path -Path $UserFolder -ChildPath "ExchangeItem_Raw.json"
$itemLogs | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath

# Process and output flattened data
$ParsedItemLogs = $itemLogs | Get-SimpleUnifiedAuditLog
if ($ParsedItemLogs) {
$ParsedItemLogs | Out-MultipleFileType -FilePrefix "ExchangeItem_Simple" -csv -json -User $User
}

# Output raw data
$itemLogs | Out-MultipleFileType -FilePrefix "ExchangeItem_Logs" -csv -json -User $User
}
else {
Out-LogFile "No ExchangeItem events found."
}

# Process ExchangeItemGroup records
Out-LogFile "Searching Unified Audit Log for ExchangeItemGroup events..."
$searchCommand = "Search-UnifiedAuditLog -UserIds $User -RecordType ExchangeItemGroup"
$groupLogs = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand

if ($groupLogs.Count -gt 0) {
Out-LogFile ("Found " + $groupLogs.Count + " ExchangeItemGroup events.")

# Write raw JSON dump
$RawJsonPath = Join-Path -Path $UserFolder -ChildPath "ExchangeItemGroup_Raw.json"
$groupLogs | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath

# Process and output flattened data
$ParsedGroupLogs = $groupLogs | Get-SimpleUnifiedAuditLog
if ($ParsedGroupLogs) {
$ParsedGroupLogs | Out-MultipleFileType -FilePrefix "ExchangeItemGroup_Simple" -csv -json -User $User
}

# Output raw data
$groupLogs | Out-MultipleFileType -FilePrefix "ExchangeItemGroup_Logs" -csv -json -User $User
}
else {
Out-LogFile "No ExchangeItemGroup events found."
}

# Summary logging
$totalEvents = ($itemLogs.Count + $groupLogs.Count)
Out-LogFile "Completed processing $totalEvents total events."
}
# If auditing is not enabled log it and move on
else {
Out-LogFile ("Auditing not enabled for " + $User)
catch {
Out-LogFile "Error retrieving audit logs: $($_.Exception.Message)" -Notice
Write-Error -ErrorRecord $_ -ErrorAction Continue
}
}
}
else {
Out-LogFile ("Auditing not enabled for " + $User) -Notice
Out-LogFile "Enable auditing to track mailbox access patterns." -Notice
}
}
}

0 comments on commit 44b9aeb

Please sign in to comment.