Reporting SendAs Audit Events for Exchange Online Mailboxes

It’s Just Different in the Cloud

One of the interesting things about Office 365 is the way that the integrated nature of the suite forces people to rethink how they previously approached tasks. Take for instance the question that Exchange administrators have been asked to answer for years: “who sent that email”?

The Development of Exchange Mailbox Auditing

When Exchange 2010 SP1 first introduced mailbox auditing, Microsoft gave administrators the tools to answer the question. The audit reports were clunky (horrible), but you could get the job done in PowerShell by running the Search-MailboxAuditLog cmdlet to search the audit records gathered for delegate activity to find the SendAs events generated when someone used that permission to send a message for another mailbox. That is, if you had enabled auditing for the mailboxes.

It took Microsoft far too long to enable auditing for all mailboxes by default. This was announced for Exchange Online in mid-2018 and eventually enabled in early 2019. However, as explained in this post, if you have Office 365 E3 licenses, you still need to manually enable mailbox auditing for mailboxes assigned those licenses.

Searching for SendAs Audit Records

To return to the famous question, tenants can use the Search-UnifiedAuditLog cmdlet to search the audit log for SendAs events and produce an answer. And that’s exactly what you see in many of the scripts offered as the basis for answering our question, including an earlier post of mine.

Adjustments Needed for Office 365

However neat such an answer is, time has moved on and the answers given previously are now wrong. Unlike Exchange on-premises, where all SendAs events are generated by delegates sending messages for another mailbox, Exchange Online processes messages sent by other workloads that can show up in audit searches and skew results unless adjustments are applied. Here are some things to consider:

  • Audit records with S-1-5-18 captured in the UserId property record the generation of a welcome message for a new team.
  • Audit records are generated when Teams sends a welcome message.
  • Audit records are generated for the group mailbox when a member posts a message to a conversation in an Outlook group using OWA. Records are not generated when messages are posted with other clients or arrive from guest members.
  • Audit records are generated for the group mailbox when someone updates a task in Planner.

A Script to Find SendAs Audit Records

With these caveats in mind, here’s a script to search for SendAs records and process SendAs audit records and identify those belonging to user/shared mailboxes and those belonging to group mailboxes. The former category is normally what people are concerned with because they’re looking for instances where someone sent a message from a mailbox rather than posting to an Outlook group or adding a comment with Planner. To help identify the two categories, we create a hash table of primary email addresses for mailboxes and groups and look that table up for each audit event.

# First populate the Recipients Hash Table with user mailboxes, group mailboxes, and shared mailboxes
CLS
Write-Host "Populating Recipients Table..."
$RecipientsTable = @{}
Try {
    $Recipients = Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox}
Catch {
    Write-Host "Can't find recipients" ; break}
# Now Populate hash table with label data  
$Recipients.ForEach( {
       $RecipientsTable.Add([String]$_.PrimarySmtpAddress, $_.RecipientTypeDetails) } )
# And include group mailboxes
$GroupMailboxes = Get-Mailbox -ResultSize Unlimited -GroupMailbox
$GroupMailboxes.ForEach( {
       $RecipientsTable.Add([String]$_.PrimarySmtpAddress, $_.RecipientTypeDetails) } )
Write-Host "Finding audit records for Send As operations..."
$Records = (Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-90) -EndDate (Get-Date).AddDays(+1) -Operations "SendAs" -ResultSize 1000)
If ($Records.Count -eq 0) {
    Write-Host "No audit records for Send As found." }
Else {
    Write-Host "Processing" $Records.Count "Send As audit records..."
    $Report = [System.Collections.Generic.List[Object]]::new() # Create output file 
    # Scan each audit record to extract information
    ForEach ($Rec in $Records) {
      $AuditData = ConvertFrom-Json $Rec.Auditdata
      $MailboxType = $RecipientsTable.Item($AuditData.MailboxOwnerUPN) # Look up hash table
      If ($MailboxType -eq "GroupMailbox") {$Reason = "Group Mailbox Send"} Else {$Reason = "Delegate Send As"}
      If ($AuditData.UserId -eq "S-1-5-18") {$UserId = "Service Account"} Else {$UserId = $AuditData.UserId}
      $ReportLine = [PSCustomObject] @{
           TimeStamp   = Get-Date($AuditData.CreationTime) -format g
           SentBy      = $AuditData.MailboxOwnerUPN
           SentAs      = $AuditData.SendAsUserSmtp
           Subject     = $AuditData.Item.Subject
           User        = $AuditData.UserId
           Action      = $AuditData.Operation
           Reason      = $Reason
           UserType    = $AuditData.UserType
           LogonType   = $AuditData.LogonType
           ClientIP    = $AuditData.ClientIP
           MailboxType = $MailboxType
           ClientInfo  = $AuditData.ClientInfoString
           Status      = $AuditData.ResultStatus }        
      $Report.Add($ReportLine) }
}
$Report | ? {$_.MailboxType -eq "UserMailbox"} | Out-GridView
$Report |Export-Csv -NoTypeInformation -Path c:\temp\SendASAuditRecords.csv
Write-Host "Report File saved in" c:\temp\SendASAuditRecords.csv

Figure 1 shows an example of some audit records found for user and shared mailboxes as generated by the script. The complete set of processed records is written out to a CSV file where the data can be parsed and analyzed to your heart’s content.

SendAs audit records for user and shared mailboxes
Figure 1: SendAs audit records for user and shared mailboxes

The script is available for download in GitHub.

The Influence of the Substrate

The problem with taking on-premises solutions like scripts to the cloud is that the solutions often don’t accommodate the way applications work and integrate. The influence of the Office 365 substrate is felt across the entire suite and is growing, which is why it’s wise to keep an eye on how scripts work as Microsoft introduces new functionality.


Chapter 21 of the Office 365 for IT Pros eBook includes many examples of how to interrogate the audit log to retrieve useful information. It’s surprising just how much you can discover if you go looking.

One Reply to “Reporting SendAs Audit Events for Exchange Online Mailboxes”

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.