functions/User/Get-HawkUserAdminAudit.ps1

Function Get-HawkUserAdminAudit {
    <#
    .SYNOPSIS
        Searches the Unified Audit logs for any commands that were run against the provided user object.
    .DESCRIPTION
        Searches the Unified Audit logs for any commands that were run against the provided user object.
        Uses Get-AllUnifiedAuditLogEntry to ensure complete retrieval of all audit records within the
        specified search period, handling pagination and large result sets automatically.
 
    .PARAMETER UserPrincipalName
        UserPrincipalName of the user you're investigating. Can be a single UPN, comma-separated list,
        or array of objects containing UPNs.
 
    .OUTPUTS
        File: Simple_User_Changes.csv
        Path: \<user>
        Description: All cmdlets that were run against the user in a simple format.
 
        File: User_Changes.csv
        Path: \<user>
        Description: Raw data of all changes made to the user.
 
        File: User_Changes_Raw.json
        Path: \<user>
        Description: Raw JSON data from audit logs.
 
        File: User_Changes_Raw.txt
        Path: \<user>
        Description: Human readable format of raw audit data.
 
    .EXAMPLE
        Get-HawkUserAdminAudit -UserPrincipalName user@company.com
 
        Gets all changes made to user@company.com and outputs them to the csv and json files.
 
    .EXAMPLE
        Get-HawkUserAdminAudit -UserPrincipalName (Get-Mailbox -Filter {CustomAttribute1 -eq "VIP"})
 
        Gets admin audit data for all mailboxes with CustomAttribute1 set to "VIP".
    #>

    [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

        # Get the mailbox name since that is what we store in the admin audit log
        $MailboxName = (Get-Mailbox -Identity $User).Name

        Out-LogFile ("Searching for changes made to: " + $MailboxName) -action

        try {
            # Build search command for Get-AllUnifiedAuditLogEntry
            $searchCommand = "Search-UnifiedAuditLog -UserIds $User -RecordType ExchangeAdmin -Operations '*'"

            # Get all changes for this user using Get-AllUnifiedAuditLogEntry
            [array]$UserChanges = Get-AllUnifiedAuditLogEntry -UnifiedSearch $searchCommand

            # If there are any results process and output them
            if ($UserChanges.Count -gt 0) {
                Out-LogFile ("Found " + $UserChanges.Count + " changes made to this user")

                # Get the user's output folder path
                $UserFolder = Join-Path -Path $Hawk.FilePath -ChildPath $User

                # Ensure user folder exists
                if (-not (Test-Path -Path $UserFolder)) {
                    New-Item -Path $UserFolder -ItemType Directory -Force | Out-Null
                }

                # Write raw AuditData to files for verification/debugging
                $RawJsonPath = Join-Path -Path $UserFolder -ChildPath "User_Changes_Raw.json"
                $UserChanges | Select-Object -ExpandProperty AuditData | Out-File -FilePath $RawJsonPath

                # Parse and format the changes using Get-SimpleUnifiedAuditLog
                $ParsedChanges = $UserChanges | Get-SimpleUnifiedAuditLog

                # Output the processed results
                if ($ParsedChanges) {
                    $ParsedChanges | Out-MultipleFileType -FilePrefix "Simple_User_Changes" -csv -json -User $User
                }

                # Output the raw changes
                $UserChanges | Out-MultipleFileType -FilePrefix "User_Changes" -csv -json -User $User
            }
            else {
                Out-LogFile "No User Changes found."
            }
        }
        catch {
            Out-LogFile "Error processing audit logs for $User : $_" -Notice
            Write-Error -ErrorRecord $_ -ErrorAction Continue
        }
    }
}