Icewolf.EXO.SpamAnalyze.psm1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
##############################################################################
# Invoke-SpamAnalyze.ps1
# Get SPAM Detail Info for Specific MessageTraceID in MessageTrace
# V2.0.0 04.05.2021 - Andres Bohren / Initial Version
# V2.0.1 07.05.2021 - Andres Bohren / Bugfixes
# V2.0.2 09.05.2021 - Andres Bohren / Bugfixes
# V2.0.3 16.06.2021 - Andres Bohren / Bugfixes Improvements
# V2.0.4 30.09.2021 - Andres Bohren / Bugfixes Improvements
##############################################################################
#Requires -Modules ExchangeOnlineManagement

Function Invoke-SpamAnalyze
{

<#
.SYNOPSIS
         
.DESCRIPTION
    Get SPAM Detail Info for Specific MessageTraceID in MessageTrace
 
.PARAMETER Recipientaddress
    The Emailaddress of the Recipient
 
.PARAMETER SenderAddress
    The Emailadress of the Sender
 
    .EXAMPLE
.\SpamAnalyze.ps1 -SenderAddress SenderAddress@domain.tld -RecipientAddress RecipientAddress@domain.tld
 
.LINK
#>


Param(
    [parameter(Mandatory=$true)][String]$RecipientAddress,
    [parameter(Mandatory=$true)][String]$SenderAddress
    )
    
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 {
    #Set PS Window Size
    #$host.UI.RawUI.BufferSize.Width = 180
    #$host.UI.RawUI.WindowSize = New-Object System.Management.Automation.Host.size(180,60)
    
    $pshost = get-host
    $pswindow = $pshost.ui.rawui
    $LanguageMode = $ExecutionContext.SessionState.LanguageMode
    If ($LanguageMode -eq "Fulllanguage"){
        if ($pswindow.WindowSize.Width -lt 220){
            $newsize = $pswindow.buffersize
            $newsize.height = 8000
            $newsize.width = 220
            $pswindow.buffersize = $newsize
            $newsize = $pswindow.windowsize
            $newsize.width = 180
            $newsize.height = 60
            $pswindow.windowsize = $newsize
        }
    }

    #Call Function to Connect to Exchange Online
    Connect-EXO

    #Check if Messagetrace is available
    Try {
        Get-Command Get-MessageTrace -ErrorAction Stop | Out-Null
    } catch { 
        Write-Host "No Permission for the Command: Get-MessageTrace. Stopping script."
        exit
    }

    #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

    If ($Null -eq $MT)
    {
        Write-Host "No Results in Message Trace found"
    } else {


        #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 -like "*Mailbox")
                    {
                        $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 MAILBOX ($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 MAILBOX ($MTRecipientAddress) 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 exists 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 exists 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-Object {$_ -match "v=spf1"}
                    $SPF = $TXT
                    If ($Null -eq $SPF)
                    {
                        Write-Host "NO SPF Record found" -ForegroundColor Yellow
                    } else {
                        $SPF
                    }

                    #DKIM
                    Write-Host "DKIM (Only checking for: selector1/selector2)" -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"                    
                    If ($DKIM -eq " ")
                    {
                        Write-Host "NO DKIM Record found" -ForegroundColor Yellow
                    } else {
                        $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
                    If ($Null -eq $DMARC)
                    {
                        Write-Host "NO DMARC Record found" -ForegroundColor Yellow
                    } else {
                        $DMARC
                    }
                    

                }
            }

        }
    }
    
}

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