Icewolf.EXO.SpamAnalyze.psm1

##############################################################################
# Invoke-SpamAnalyze.ps1
# Get SPAM Detail Info for Specific MessageTraceID in MessageTrace
# V2.0 04.05.2021 - Andres Bohren / Initial Version
#
#$MT = Get-MessageTrace -StartDate (get-date).AddDays(-10) -EndDate (get-date) -SenderAddress andres.bohren@gmail.com
#$MT | Format-Table Received, SenderAddress, RecipientAddress, Subject, Status, MessageTraceID
#NoSpam
#$MTD = Get-MessageTraceDetail -MessageTraceId 5d40e9c4-c0e9-4c31-e94c-08d90a15b65c -RecipientAddress a.bohren@icewolf.ch -StartDate (get-date).AddDays(-10) -EndDate (get-date)
#Quarantine
#$MTD = Get-MessageTraceDetail -MessageTraceId 5b018c12-df4a-4300-df60-08d90bca587d -RecipientAddress a.bohren@icewolf.ch -StartDate (get-date).AddDays(-10) -EndDate (get-date)
#$MTD
#$Spam = $MTD | where {$_.Event -eq "Spam"}
#[xml]$xmlS = $Spam.Data
#$xmls.root.MEP | fl
#[xml]$xml1 = $MTD[0].data
#$xml1.root.MEP | fl
#[xml]$xml3 = $MTD[3].data
#$xml3.root.MEP | fl
#[xml]$xml4 = $MTD[4].data
#$xml4.root.MEP | fl
##############################################################################
#Requires -Modules ExchangeOnlineManagement

Function Invoke-SpamAnalyze
{

<#
.SYNOPSIS
         
.DESCRIPTION
    Get SPAM Detail Info for Specific MessageTraceID in MessageTrace
 
.PARAMETER Recipientaddress
    The mailbox on whicht the permission will be set
 
.PARAMETER SenderAddress
    The mailbox on whicht the permission will be set
 
    .EXAMPLE
.\SpamAnalyze.ps1 -SenderAddress SenderAddress@domain.tld -RecipientAddress RecipientAddress@domain.tld
 
.LINK
#>


Param(
    [parameter(Mandatory=$false)][String]$RecipientAddress = $null,
    [parameter(Mandatory=$false)][String]$SenderAddress = $null
    )
    
Begin {
    ##############################################################################
    # Connect to Exchange Online
    ##############################################################################
    Function Connect-EXO {
            
        If ($Null -eq (Get-PsSession | Where-Object {$_.ComputerName -eq "outlook.office365.com"})) 
        {
            Write-Host "Connect to Exchange Online..." -f Gray
            Connect-ExchangeOnline -ShowBanner:$false

            If ($Null -eq (Get-PsSession | Where-Object {$_.ComputerName -like "*compliance.protection.outlook.com"}))
            {
                Write-Host "Connect to Security and Compliance..." -f Gray
                Connect-IPPSSession  -WarningAction Silentlycontinue    
            } else {
                Write-Host "Connection to Security and Compliance already exists" -ForegroundColor Green
            }

        }
        Else {
            Write-Host "Connection to Exchange Online already exists" -ForegroundColor Green

            If ($Null -eq (Get-PsSession | Where-Object {$_.ComputerName -like "*compliance.protection.outlook.com"}))
            {
                Write-Host "Connect to Security and Compliance..." -f Gray
                Connect-IPPSSession  -WarningAction Silentlycontinue    
            } else {
                Write-Host "Connection to Security and Compliance already exists" -ForegroundColor Green
            }

        }
    }

    ##############################################################################
    # Disconnect from Exchange Online
    ##############################################################################
    Function Disconnect-EXO 
    {
                Write-Host "Disconnect from Exchange Online" -f Gray
                #fWrite-Log -fLogtext "Disconnect from Exchange Online"
                Get-PSSession | Where-Object {($_.ComputerName -eq "outlook.office365.com") -AND ($_.ConfigurationName -eq "Microsoft.Exchange")} | Remove-PSSession
                Get-PSSession | Where-Object {($_.ComputerName -like "compliance.protection.outlook.com") -AND ($_.ConfigurationName -eq "Microsoft.Exchange")} | Remove-PSSession
                
    }
    

    ##############################################################################
    # Check MessageTraceDetail
    ##############################################################################
    Function Get-SPAMinfo {
        Param(
            [parameter(Mandatory=$false)][String]$RecipientAddress,
            [parameter(Mandatory=$false)][String]$SenderAddress,
            [parameter(Mandatory=$true)][String]$MessageTraceId
            )
        
        $Start = (Get-Date).AddDays(-10) 
        $End = (Get-Date)

        Write-Host "Message events:" -ForegroundColor Magenta
        $MTDetail = Get-MessageTraceDetail -MessageTraceId $MessageTraceId -RecipientAddress $RecipientAddress -SenderAddress $SenderAddress -StartDate $Start -EndDate $End | Sort-Object Date

        $MTEventFail = $MTDetail | Where-Object {$_.event -eq "Failed"}
        If ($Null -ne $MTEventFail) {
            Write-Host "Failed-Event: " -ForegroundColor Magenta
            Write-Host (" Action: " +$MTEventFail.action )
            Write-Host
        }        
        $MTEventMal = $MTDetail | Where-Object {$_.event -eq "Malware"}
        If ($Null -ne $MTEventMal) {
            Write-Host "Malware-Event: " -ForegroundColor Magenta
            Write-Host (" Action: " +$MTEventMal.action )
            Write-Host
        }
        $MTEventSPM = $MTDetail | Where-Object {$_.event -eq "Spam"} | Select-Object -uniq
        # SPAM Detail
        If ($Null -ne $MTEventSPM) {
            Write-Host "SPAM-Event: " -ForegroundColor Magenta
            Write-Host (" Action: " +$MTEventSPM.action )
            Write-Host
            Write-Host "SPAM-Event Details:" -ForegroundColor Magenta
            Write-Host "Anti-spam message headers: https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/anti-spam-message-headers" -f Cyan
            Write-Host "Spam confidence levels: https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/spam-confidence-levels" -f Cyan
            [xml]$xmlS = $MTEventSPM.Data
            $RcptCount  = ($xmlS.root.MEP | Where-Object {$_.Name -eq "RcptCount"})
            $DI         = ($xmlS.root.MEP | Where-Object {$_.Name -eq "DI"})
            $SCL        = ($xmlS.root.MEP | Where-Object {$_.Name -eq "SCL"})
            $Score        = ($xmlS.root.MEP | Where-Object {$_.Name -eq "Score"})
            $SFV        = ($xmlS.root.MEP | Where-Object {$_.Name -eq "SFV"})
            $ClientIP   = ($xmlS.root.MEP | Where-Object {$_.Name -eq "CIP"})
            $Country    = ($xmlS.root.MEP | Where-Object {$_.Name -eq "Ctry"})
            $HeloString = ($xmlS.root.MEP | Where-Object {$_.Name -eq "H"})
            $ReturnPath = ($xmlS.root.MEP | Where-Object {$_.Name -eq "ReturnPath"})
            $Language   = ($xmlS.root.MEP | Where-Object {$_.Name -eq "Language"})
            Write-Host (" RecipientCount: " +$RcptCount.Integer)
            switch ($DI.String) {
                "SB" { $DI = "(SB) The sender of the message was blocked" }
                "SQ" { $DI = "(SQ) The message was quarantined" }
                "SD" { $DI = "(SD) The message was deleted" }
                "SJ" { $DI = "(SJ) The message was sent to the recipient's Junk Email folder" }
                "SN" { $DI = "(SN) The message was routed through the higher risk delivery pool" }
                "SO" { $DI = "(SO) The message was routed through the normal outbound delivery pool" }
            }
            Write-Host (" DI: " +$DI)
            # Color for SCL
            switch ($SCL.Integer) {
                -1 { $cSCL = "Green"; $Folder = "Inbox" }
                0 { $cSCL = "Green"; $Folder = "Inbox" }
                1 { $cSCL = "Green"; $Folder = "Inbox" }
                2 { $cSCL = "Green"; $Folder = "Inbox" }
                3 { $cSCL = "Green"; $Folder = "Inbox" }
                4 { $cSCL = "Green"; $Folder = "Inbox" }
                5 { $cSCL = "Yellow"; $Folder = "Junk-E-Mail" }
                6 { $cSCL = "Yellow"; $Folder = "Junk-E-Mail" }
                7 { $cSCL = "Red"; $Folder = "Quarantaine" }
                8 { $cSCL = "Red"; $Folder = "Quarantaine" }
                9 { $cSCL = "Red"; $Folder = "Quarantaine" }
            }
            Write-Host (" SpamConfidenceLevel (SCL): "+$SCL.Integer +" Deliver to: " +$Folder +")") -f $cSCL
            Write-Host (" SpamScoreLevel (Score): "+$Score.Integer )
            switch ($SFV.String) 
            {
                "BLK" { $SFV = "(BLK) Filtering was skipped and the message was blocked because it originated from a blocked sender" }
                "NSPM" { $SFV = "(NSPM) The message was marked as non-spam and was sent to the intended recipients" }
                "SFE" { $SFV = "(SFE) Filtering was skipped and the message was allowed because it was sent from an address in a user's Safe Senders list"}
                "SKA" { $SFV = "(SKA) The message skipped spam filtering and was delivered to the Inbox because the sender was in the allowed senders list or allowed domains list in an anti-spam policy"}
                "SKB" { $SFV = "(SKB) The message skipped spam filtering and was delivered to the Inbox because the sender was in the allowed senders list or allowed domains list in an anti-spam policy"}
                "SKI" { $SFV = "(SKI) Similar to SFV:SKN, the message skipped spam filtering for another reason (for example, an intra-organizational email within a tenant)"}
                "SKN" { $SFV = "(SKN) The message was marked as non-spam prior to being processed by spam filtering. For example, the message was marked as SCL -1 or Bypass spam filtering by a mail flow rule"}
                "SKQ" { $SFV = "(SKQ) The message was released from the quarantine and was sent to the intended recipients"}
                "SKS" { $SFV = "(SKS) The message was marked as spam prior to being processed by the content filter" }
                "SPM" { $SFV = "(SPM) The message was marked as spam by spam filtering" }
                            
            }
            Write-Host (" SpamFilterVerdikt (SFV): " +$SFV)
            Write-Host (" SenderClientIP (CIP): " +$ClientIP.String)
            Write-Host (" Country (CTRY): " +$Country.String)
            Write-Host (" HeloString (H): " +$HeloString.String)
            Write-Host (" ReturnPath: " +$ReturnPath.String)
            Write-Host (" Language: " +$Language.String)
            Write-Host    

        } Else {
            Write-Host "SPAM-Event: " -ForegroundColor Magenta
            Write-Host (" INFO: This mail contains no 'Spam' event ") -f Cyan
            Write-Host
        }
    }
}

Process {
    #Call Function to Connect to Exchange Online
    Connect-EXO

    #Set Start- and Enddate for Messagetrace
    $Start = ((Get-Date).AddDays(-10))
    $End = Get-Date
    
    #Messagetrace depending on Parameters
    If ($SenderAddress -ne $Null)
    {
        If ($RecipientAddress -ne $Null)
        {
            $MT = Get-MessageTrace -StartDate (get-date).AddDays(-10) -EndDate (get-date) -SenderAddress $SenderAddress -RecipientAddress $RecipientAddress 
        } else {
            $MT = Get-MessageTrace -StartDate (get-date).AddDays(-10) -EndDate (get-date) -SenderAddress $SenderAddress 
        }
    } else {
        #SenderAddress = $Null / RecipientAddress populated
        $MT = Get-MessageTrace -StartDate (get-date).AddDays(-10) -EndDate (get-date) -RecipientAddress $RecipientAddress  
    }
    $MT | Format-Table Received, SenderAddress, RecipientAddress, Subject, Status, MessageTraceID


    #Input MessageTraceID
    $readhost = Read-Host "MessageTraceID?"
    If ($readhost -eq "")
    {
        Write-Host "Not a MessageTraceID... Stopping Script"
    } else {
        Write-Host "DEBUG: Readhost: $readhost"
        Foreach ($Line in $MT)
        {
            If ($readhost -eq $Line.MessageTraceId)
            {
                
                #Write-Host "DEBUG: MessageTraceID: $($Line.MessageTraceId)"
                #Write-Host "DEBUG: Sender: $($Line.Senderaddress)"
                #Write-Host "DEBUG: Recipient: $($Line.RecipientAddress)"
                $MessageTraceId = $Line.MessageTraceId
                $MTSenderAddress = $Line.Senderaddress
                $MTRecipientAddress = $Line.RecipientAddress
                $MTStatus = $Line.Status
                $MTSubject = $Line.Subject
                $MTReceived = $Line.Received
                $MTMessageID = $Line.MessageID

                #Infos from Message Trace
                Write-Host
                Write-Host "E-Mail Detail:" -ForegroundColor Magenta
                Write-Host " Message ID: $MTMessageID"
                Write-Host " Received: $MTReceived"
                Write-Host " Sender: $MTSenderAddress"
                Write-Host " Recipient: $MTRecipientAddress"
                Write-Host " Subject: $MTSubject"
                Write-Host " Status: $MTStatus"
                Write-Host

                #Check Recipient
                $ExoRecipient = Get-Recipient -Identity $MTRecipientAddress
                #$ExoRecipient
                $RecipientTypeDetails = $ExoRecipient.RecipientTypeDetails

                Write-Host "Recipient Details" -ForegroundColor Magenta
                Write-Host " RecipientTypeDetails: $RecipientTypeDetails"
                Write-Host

                #JunkMailConfiguration of Mailbox
                $SenderDomain = ($SenderAddress.Split("@")[1])
                If ($RecipientTypeDetails -eq "UserMailbox")
                {
                    $JMC = Get-MailboxJunkEmailConfiguration -Identity $MTRecipientAddress
                    If ($NULL -ne $JMC)
                    {
                        Write-Host "Recipient JunkMailConfiguration" -ForegroundColor Magenta
                        Write-Host " TrustedListsOnly: $($JMC.TrustedListsOnly)"
                        Write-Host " ContactsTrusted: $($JMC.ContactsTrusted)"
                        Write-Host

                        Write-Host "Check if $MTSenderAddress exists in $MTRecipientAddress Trusted-/BlockedSenders list: " -ForegroundColor Magenta        
                        If ($JMC.TrustedSendersAndDomains -contains $MTSenderAddress)
                        {
                            Write-Host " USER Junk-E-Mail Config: Found in 'TrustedSendersAndDomains'" -f Green
                        } Else {
                            Write-Host " USER Junk-E-Mail Config: Not found in 'TrustedSendersAndDomains'" -f White
                        }
                        
                        If ($JMC.BlockedSendersAndDomains -contains $MTSenderAddress)
                        {
                            Write-Host " USER Junk-E-Mail Config: Found in 'BlockedSendersAndDomains'" -f Red
                        } Else {
                            Write-Host " USER Junk-E-Mail Config: Not found in 'BlockedSendersAndDomains'" -f White
                        }
                        Write-Host
                        
                        Write-Host "Check if $SenderDomain exists in $Recipient Trusted-/BlockedSenders list: " -ForegroundColor Magenta    
                        If ($JMC.TrustedSendersAndDomains -contains $SenderDomain)
                        {
                            Write-Host " USER Junk-E-Mail Config: Found in 'TrustedSendersAndDomains'" -f Green
                        } Else {
                            Write-Host " USER Junk-E-Mail Config: Not found in 'TrustedSendersAndDomains'" -f White
                        }
                        
                        If ($JMC.BlockedSendersAndDomains -contains $SenderDomain)
                        {
                            Write-Host " USER Junk-E-Mail Config: Found in 'BlockedSendersAndDomains'" -f Red
                        } Else {
                            Write-Host " USER Junk-E-Mail Config: Not found in 'BlockedSendersAndDomains'" -f White
                        }
                        Write-Host

                    }                    
                }

                   #GLOBALConfig
                Write-Host "Check if $MTSenderAddress found in GLOBAL Trusted-/BlockedSender list: " -ForegroundColor Magenta
                $GLOBALJunkConfig = Get-HostedContentFilterPolicy
                #Allowed Senders
                If ($GLOBALJunkConfig.AllowedSenders -match $MTSenderAddress)
                {
                    Write-Host " GLOBAL EAC SpamFilter: Found in 'AllowedSenders'" -f Green
                } Else {
                    Write-Host " GLOBAL EAC SpamFilter: Not found in 'AllowedSenders'" -f White
                }

                #Blocked Senders
                If ($GLOBALJunkConfig.BlockedSenders -match $MTSenderAddress)
                {
                    Write-Host " GLOBAL EAC SpamFilter: Found in 'BlockedSenders'" -f Red
                } Else {
                    Write-Host " GLOBAL EAC SpamFilter: Not found in 'BlockedSenders'" -f White
                }
                Write-Host

                Write-Host "Check if $SenderDomain found in GLOBAL Allowed-/BlockedSenderDomain list: " -ForegroundColor Magenta
                #Allowed Domains
                If ($GLOBALJunkConfig.AllowedSenderDomains.Domain -contains $SenderDomain)
                {
                    Write-Host " GLOBAL EAC SpamFilter: Found in 'AllowedSenderDomains'" -f Green
                } Else {
                    Write-Host " GLOBAL EAC SpamFilter: Not found in 'AllowedSenderDomains'" -f White
                }

                #Allowed Senders
                If ($GLOBALJunkConfig.BlockedSenderDomains.Domain -contains $SenderDomain)
                {
                    Write-Host " GLOBAL EAC SpamFilter: Found in 'BlockedSenderDomains'" -f Red
                } Else {
                    Write-Host " GLOBAL EAC SpamFilter: Not found in 'BlockedSenderDomains'" -f White
                }
                Write-Host


                Get-SPAMinfo -RecipientAddress $MTRecipientAddress -SenderAddress $MTSenderAddress -MessageTraceId $MessageTraceId

                #DNS Records
                Write-Host "DNS Records of $SenderDomain" -ForegroundColor Magenta
                #NS
                Write-Host "NS" -ForegroundColor Magenta
                $json = Invoke-RestMethod -URI "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=$SenderDomain&type=NS"
                [string]$NS = $json.Answer.data
                $NS

                #MX
                Write-Host "MX" -ForegroundColor Magenta
                $json = Invoke-RestMethod -URI "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=$SenderDomain&type=MX"
                [string]$MX = $json.Answer.data
                $MX

                #SPF
                Write-Host "SPF" -ForegroundColor Magenta
                $json = Invoke-RestMethod -URI "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=$SenderDomain&type=TXT"
                $TXT = $json.Answer.data
                $TXT = $TXT | where {$_ -match "v=spf1"}
                $SPF = $TXT
                $SPF


                #DKIM
                Write-Host "DKIM" -ForegroundColor Magenta
                $json = Invoke-RestMethod -URI "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=Selector1._domainkey.$SenderDomain&type=CNAME"
                $DKIM1 = $json.Answer.data
                $json = Invoke-RestMethod -URI "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=Selector2._domainkey.$SenderDomain&type=CNAME"
                $DKIM2 = $json.Answer.data
                [string]$DKIM = "$DKIM1 $DKIM2"
                $DKIM

                #DMARC
                Write-Host "DMARC" -ForegroundColor Magenta
                $json = Invoke-RestMethod -URI "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=_dmarc.$SenderDomain&type=TXT"
                $DMARC = $json.Answer.data
                $DMARC

            }
        }

    }
    break
    Get-SPAMinfo -RecipientAddress $RecipientAddress -SenderAddress $SenderAddress -MessageTraceId $MessageTraceId
}

End {
    #Disconnect from Exchange Online and
    #Disconnect-EXO
}
}