Powershell : Analyzing message headers (for your mailbox)

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
}

Previous Post Next Post

نموذج الاتصال