Find unused SMTP proxy addresses (10 days)
Check user and shared mailboxes to find SMTP proxy addresses that have not been used to send or receive email in the last 10 days, using Exchange Online message trace data.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-ExchangeOnline -ShowBanner:$False -ErrorAction Stop
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),[int] $BatchSize = 2000)If ($Null -eq (Get-ConnectionInformation)) {Connect-ExchangeOnline -ShowBanner:$False -ErrorAction Stop}# Message trace date is kept for a maximum of 10 daysWrite-Host ("Message trace data will be analyzed between {0} and {1}" -f (Get-Date $StartDate -format 'dd-MMM-yyyy HH:mm'), (Get-Date $EndDate -format 'dd-MMM-yyyy HH:mm'))Write-Host "Fetching message trace data to analyze"[array]$Messages = $Null[int]$BatchSizeForMessages = 2000# original code [array]$MessagePage = Get-MessageTrace -StartDate $StartDate -EndDate $EndDate -PageSize 1000 -Page $i -Status "Delivered"Try {# The warning action is suppressed here because we don't want to see warnings when more data is available[array]$MessagePage = Get-MessageTraceV2 -StartDate $StartDate -EndDate $EndDate `-ResultSize $BatchSizeForMessages -Status "Delivered" -ErrorAction Stop -WarningAction SilentlyContinue$Messages += $MessagePage} Catch {Write-Host ("Error fetching message trace data: {0}" -f $_.Exception.Message)Break}If ($MessagePage.count -eq $BatchSizeForMessages) {Do {Write-Host ("Fetched {0} messages so far" -f $Messages.count)$LastMessageFetched = $MessagePage[-1]$LastMessageFetchedDate = $LastMessageFetched.Received.ToString("O")$LastMessageFetchedRecipient = $LastMessageFetched.RecipientAddress# Fetch the next page of messages[array]$MessagePage = Get-MessageTraceV2 -StartDate $StartDate -EndDate $LastMessageFetchedDate `-StartingRecipientAddress $LastMessageFetchedRecipient -ResultSize $BatchSizeForMessages -Status "Delivered" -ErrorAction Stop -WarningAction SilentlyContinueIf ($MessagePage) {$Messages += $MessagePage}} While ($MessagePage.count -eq $BatchSizeForMessages)}# Remove Exchange Online public folder hierarchy synchronization messages$Messages = $Messages | Where-Object {$_.Subject -NotLike "*HierarchySync*"}# Now, do we have any messsages to process?If ($Messages.count -eq 0) {Write-Host "No messages found for analysis"Break} Else {Write-Host ("After excluding system messages, there are {0} messages for analysis" -f $Messages.count)}[array]$Domains = Get-AcceptedDomain | Select-Object -ExpandProperty DomainName$Report = [System.Collections.Generic.List[Object]]::new()ForEach ($M in $Messages) {$Direction = "Inbound"$SenderDomain = $M.SenderAddress.Split("@")[1]$RecipientDomain = $M.RecipientAddress.Split("@")[1]If ($SenderDomain -in $Domains) {$Direction = "Outbound"}$ReportLine = [PSCustomObject]@{TimeStamp = $M.ReceivedSender = $M.SenderAddressRecipient = $M.RecipientAddressSubject = $M.SubjectStatus = $M.StatusDirection = $DirectionSenderDomain = $SenderDomainRecipientDomain = $RecipientDomain}$Report.Add($ReportLine)}# Build an array of email addresses from this tenant used to send or receive messages[array]$Senders = $Report | Where-Object {$_.SenderDomain -in $Domains} | Sort-Object Sender -Unique | Select-Object -ExpandProperty Sender[array]$Recipients = $Report | Where-Object {$_.RecipientDomain -in $Domains} | Sort-Object Recipient -Unique | Select-Object -ExpandProperty Recipient[array]$AllAddresses = $Senders + $Recipients | Sort-Object -Unique$ReportAddresses = [System.Collections.Generic.List[Object]]::new()# Find mailboxes[array]$Mailboxes = Get-ExoMailbox -ResultSize Unlimited -Properties EmailAddresses -RecipientTypeDetails UserMailbox, SharedMailbox | Sort-Object DisplayName# This code to check against the array of all senders and recipients in the last 10 daysForEach ($Mbx in $Mailboxes) {$MbxAddresses = $Mbx.EmailAddresses | Where-Object {$_ -like "smtp:*"}ForEach ($Address in $MbxAddresses) {$SmtpAddress = $Address.Substring(5) # Remove the smtp: prefixIf ($SmtpAddress -notin $AllAddresses) {$ReportLine = [PSCustomObject]@{DisplayName = $Mbx.DisplayNamePrimarySmtpAddress = $Mbx.PrimarySmtpAddressAlias = $Mbx.AliasMailboxType = $Mbx.RecipientTypeDetailsUnusedProxyAddress = $SmtpAddressCheckType = "Sender"}$ReportAddresses.Add($ReportLine)}}}$ReportAddresses | Out-GridViewgenerate an output fileIf (Get-Module ImportExcel -ListAvailable) {$ExcelGenerated = $TrueImport-Module ImportExcel -ErrorAction SilentlyContinue$ExcelOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\UnusedProxyAddresses.xlsx"If (Test-Path $ExcelOutputFile) {Remove-Item $ExcelOutputFile -ErrorAction SilentlyContinue}$ReportAddresses | Export-Excel -Path $ExcelOutputFile -WorksheetName "Unused Proxy Addresses" -Title ("Unused Proxy Addresses Report {0}" -f (Get-Date -format 'dd-MMM-yyyy')) -TitleBold -TableName "UnusedProxyAddresses"} Else {$CSVOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\UnusedProxyAddresses.CSV"$ReportAddresses | Export-Csv -Path $CSVOutputFile -NoTypeInformation -Encoding Utf8}If ($ExcelGenerated) {Write-Host ("Excel worksheet output written to {0}" -f $ExcelOutputFile)} Else {Write-Host ("CSV output file written to {0}" -f $CSVOutputFile)}
Parameters
-LookbackDays10Number of days back to search message trace data (Exchange Online limit is 10 days).-StartDate(Get-Date).AddDays(-10)Start of the message trace search window.-EndDate(Get-Date)End of the message trace search window.-BatchSize2000Maximum number of message trace records to fetch per batch.