This particular article for came about not because it’s something new but it’s something I waned t to see if I could script, and I must say, it was quite an interesting journey.
The whole point of the script is to give you a list of messages that you have access to anyway, because those messages are in your inbox, so when you run the script, it will connect your mailbox and retrieve the top 100 messages in your inbox (regardless of the folder)
It will also tell you the sender and the subject title, it will also put a number next to each message so you can select the message you wish to analyze like this:
You will the Prompted which message you would like to analyze that should look something like this:
Now, you need to enter the message you wish the script to analyze And after a short moment, it will give you vital message details, including what servers the messages have been through, how long it took to deliver the message, any certificates if present - and finally, if it’s been through the usual email service that you’re organization uses.
That should look something like this:
If it is not been through expected servers for your organization, you can then get a warning to tell you that this email could be potentially malicious or phishing as below:
The trusted email configuration takes wildcard style domain names, so this can be easily customized for your individual organizational requirements.
Yes, I’m aware you can do the steps manually by copying your message headers And then use one of the many analysis websites - but there’s absolutely no fun in doing that yourself when you can script it.
Script : MessageMHA.ps1
# Import required modules
Import-Module ExchangeOnlineManagement
function Connect-ToExchangeOnline {
try {
$global:userEmail = Read-Host "Enter your email address"
Connect-ExchangeOnline -UserPrincipalName $userEmail
Write-Host "Successfully connected to Exchange Online" -ForegroundColor Green
return $true
}
catch {
Write-Host "Failed to connect to Exchange Online: $_" -ForegroundColor Red
return $false
}
}
function Get-EmailList {
try {
$startTime = (Get-Date).AddDays(-10)
$endTime = Get-Date
$emails = Get-MessageTrace -RecipientAddress $userEmail -StartDate $startTime -EndDate $endTime |
Select-Object -First 100
if ($emails.Count -eq 0) {
Write-Host "No emails found." -ForegroundColor Yellow
return $null
}
Write-Host "`nLast 100 emails:" -ForegroundColor Cyan
for ($i = 0; $i -lt $emails.Count; $i++) {
Write-Host "$($i + 1). Subject: $($emails[$i].Subject)"
Write-Host " From: $($emails[$i].FromAddress)"
Write-Host " Received: $($emails[$i].Received)`n"
}
return $emails
}
catch {
Write-Host "Error retrieving emails: $_" -ForegroundColor Red
return $null
}
}
function Check-TrustedServers {
param (
[Parameter(Mandatory=$true)]
[Array]$receivedEvents
)
$trustedPatterns = @(
'prod.outlook.com',
'pphosted',
'.SEVERNTRENT.CO.UK'
)
$foundPatterns = @()
$messagePath = $receivedEvents.Detail -join " "
foreach ($pattern in $trustedPatterns) {
if ($messagePath -match [regex]::Escape($pattern)) {
$foundPatterns += $pattern
}
}
return @{
Found = $foundPatterns
IsSecure = $foundPatterns.Count -gt 0 # True if at least one pattern is found
}
}
function Get-MessagePathAnalysis {
param (
[Parameter(Mandatory=$true)]
$message
)
try {
$messageId = $message.MessageId
$fullMessage = Get-MessageTrace -MessageId $messageId | Get-MessageTraceDetail
# Get message path (server hops)
Write-Host "`nMessage Path:" -ForegroundColor Cyan
$receivedEvents = $fullMessage | Where-Object { $_.Event -eq "Receive" } | Sort-Object Date
foreach ($hop in $receivedEvents) {
Write-Host "→ $($hop.Detail)" -ForegroundColor Green
}
# Check trusted servers
$serverCheck = Check-TrustedServers -receivedEvents $receivedEvents
Write-Host "`nTrusted Server Analysis:" -ForegroundColor Cyan
if (-not $serverCheck.IsSecure) {
Write-Host "`n⚠️ SECURITY ALERT: This message may be suspicious or malicious!" -ForegroundColor Red
Write-Host " Message did not pass through any known trusted servers." -ForegroundColor Red
} else {
Write-Host "✓ Message passed through trusted server(s):" -ForegroundColor Green
foreach ($found in $serverCheck.Found) {
Write-Host "✓ $found" -ForegroundColor Green
}
}
# Calculate transit time
if ($receivedEvents) {
$timeSpan = New-TimeSpan -Start $receivedEvents[0].Date -End $receivedEvents[-1].Date
Write-Host "`nDelivery Time:" -ForegroundColor Cyan
Write-Host "Total transit time: $($timeSpan.TotalSeconds) seconds" -ForegroundColor Green
}
# Look for SSL/TLS information
Write-Host "`nSSL/TLS Information:" -ForegroundColor Cyan
$tlsEvents = $fullMessage | Where-Object { $_.Event -match "Transport" -and $_.Detail -match "TLS" }
if ($tlsEvents) {
foreach ($tlsInfo in $tlsEvents) {
Write-Host $tlsInfo.Detail -ForegroundColor Green
}
}
else {
Write-Host "No SSL/TLS information found" -ForegroundColor Yellow
}
}
catch {
Write-Host "Error analyzing message: $_" -ForegroundColor Red
}
}
# Main script
Clear-Host
Write-Host "Message Path Analysis Tool" -ForegroundColor Cyan
Write-Host "=========================" -ForegroundColor Cyan
if (Connect-ToExchangeOnline) {
$emails = Get-EmailList
if ($emails) {
$selection = Read-Host "`nEnter the number of the email you want to analyze (1-$($emails.Count))"
$selectedEmail = $emails[$selection - 1]
Get-MessagePathAnalysis $selectedEmail
}
Disconnect-ExchangeOnline -Confirm:$false
}