Entra / Microsoft 365 · Exchange Online
Report external email sent
Script to demonstrate how to create a report about the external email activity of individuals identified through.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -Scope "Mail.Send, Mail.ReadWrite" -NoWelcome
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([int] $LookbackDays = 10,[string] $StartDate = (Get-Date).AddDays(-$LookbackDays),[string] $EndDate = "Get-Date")$ModulesLoaded = Get-Module | Select-Object NameIf (!($ModulesLoaded -match "ExchangeOnlineManagement")){Write-Host "Please connect to the Exchange Online Management module and then restart the script"; break}# Connect to the Microsoft Graph PowerShell SDK so that we can send emailConnect-MgGraph -Scope "Mail.Send, Mail.ReadWrite" -NoWelcome$TenantName = (Get-OrganizationConfig).DisplayName$ExternalHTMLFile = "c:\temp\ExternalEmailSent.html"[array]$Users = Get-DistributionGroupMember -Identity Monitored.Users | Select-Object DisplayName, PrimarySmtpAddress, RecipientTypeDetails# Drop anything else but mailboxes[array]$Users = $Users | Where-Object {$_.RecipientTypeDetails -eq "UserMailbox"}Write-Host ("Checking external email for {0} mailboxes" -f $Users.count)$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($User in $Users) {Write-Host ("Checking messages sent by {0}" -f $User.DisplayName)# Get message information for the last ten days and filter so that we end up with just external addresses[string]$SenderAddress = $User.PrimarySmtpAddress.toString()# Old code - Get-MessageTrace cmdlet will be deprecated in the future, so we use Get-MessageTraceV2 instead# [array]$Messages = Get-MessageTrace -StartDate $StartDate -EndDate $EndDate -SenderAddress $SenderAddress -Status Delivered | Where-Object {$_.RecipientAddress -notlike "*@Office365itpros*"}[array]$Messages = Get-MessageTraceV2 -StartDate $StartDate -EndDate $EndDate -SenderAddress $SenderAddress -Status Delivered | Where-Object {$_.RecipientAddress -notlike "*@Office365itpros*"}ForEach ($M in $Messages) {$ReportLine = [PSCustomObject][Ordered]@{Date = Get-Date($M.Received) -format gUser = $M.SenderAddressRecipient = $M.RecipientAddressSubject = $M.SubjectMessageId = $M.MessageId}$Report.Add($ReportLine)} #End Foreach messages} # End ForEach Users# Create HTML content$Report = $Report | Sort-Object User$Today = Get-Date -format f$HtmlStart ='<html><head><font face="Segoe UI"><Title>External Email Activity Report</Title></font></p><p><font face="Segoe UI"><h2>Tenant: ' + ($TenantName) + '</h2></p><p><font face="Segoe UI"><h3>Generated: ' + $Today + '</h3></font></p><table align="center" border="1" cellpadding="1" cellspacing="1" style="background-color:#e6e6fa; border-style:hidden"><caption><h1><span style="font-size:30px"><strong><span style="color:#3498db">External Email Analysis Report</span></strong></span></h1></caption><thead><tr><th scope="col">Timestamp</th><th scope="col">Semder</th><th scope="col">Recipient</th><th scope="col">Subject</th></tr></thead><tbody>'# Insert individual message infoForEach ($R in $Report) {$DataLines += "<tr><td>$($R.Date)</td><td>$($R.User)</td><td>$($R.'Recipient')</td><td>$($R.'Subject')</td></tr>"}$Htmlend = "</tbody></table></body></html>'"$Body = $HTMLStart + $DataLines + $HTMLEnd$Body | Out-File $ExternalCSVFile# Define who the message comes from (the signed in user for the Graph session) and the recipient (the person who manages the DL)$MsgFrom = (Get-MgContext).Account[string]$EmailRecipient = (Get-DistributionGroup -Identity Monitored.Users).ManagedBy[string]$EmailRecipientAddress = (Get-EXOMailbox -Identity $EmailRecipient).PrimarySmtpAddress$MsgSubject = "User External Email Report"# Add the HTML file as an attachment$EncodedAttachmentFile = [Convert]::ToBase64String([IO.File]::ReadAllBytes($ExternalHTMLFile))$MsgAttachments = @(@{"@odata.type" = "#microsoft.graph.fileAttachment"Name = ($ExternalHTMLFile -split '\\')[-1]ContentBytes = $EncodedAttachmentFile})# Add the recipient using the mailbox's primary SMTP address$EmailAddress = @{address = $EmailRecipientAddress}$EmailToRecipient = @{EmailAddress = $EmailAddress}Write-Host "Sending report to" $EmailRecipientAddress$HtmlHeader = "<h2>User External Email Activity Report</h2>"$HtmlMsg = "</body></html>" + $htmlheader + $Body + "<p>"# Construct the message body$MessageBody = @{Content = "$($HtmlMsg)"ContentType = 'html'}# Create a draft message in the signed-in user's mailboxTry {Write-Host "Creating message to send..."$NewMessage = New-MgUserMessage -UserId $MsgFrom -Body $MessageBody -ToRecipients $EmailToRecipient -Subject $MsgSubject -Attachments $MsgAttachments -ErrorAction Stop# Send the message} Catch {Write-Host "Error creating message: $($_.Exception.Message)"Break}Try {Send-MgUserMessage -UserId $MsgFrom -MessageId $NewMessage.Id -ErrorAction StopWrite-Host ("Report emailed to {0} and HTML file is available at {1}" -f $EmailRecipientAddress, $ExternalHTMLFile)} Catch {Write-Host "Error sending message: $($_.Exception.Message)"}
Parameters
ParameterDefaultNotes
-LookbackDays10Number of days back to search the unified audit log.-StartDate(Get-Date).AddDays(-10)Start of the reporting window.-EndDateGet-DateEnd of the reporting window.Attribution
Author
Office365itpros