PSBlackListChecker.psm1

[string[]] $Script:BlackLists = @(
    'b.barracudacentral.org'
    'spam.rbl.msrbl.net'
    'zen.spamhaus.org'
    'bl.deadbeef.com'
    'bl.emailbasura.org'
    'bl.spamcannibal.org'
    'bl.spamcop.net'
    'blackholes.five-ten-sg.com'
    'blacklist.woody.ch'
    'bogons.cymru.com'
    'cbl.abuseat.org'
    'cdl.anti-spam.org.cn'
    'combined.abuse.ch'
    'combined.rbl.msrbl.net'
    'db.wpbl.info'
    'dnsbl-1.uceprotect.net'
    'dnsbl-2.uceprotect.net'
    'dnsbl-3.uceprotect.net'
    # 'dnsbl.ahbl.org' # as per https://ahbl.org/ was terminated in 2015
    'dnsbl.cyberlogic.net'
    'dnsbl.inps.de'
    'dnsbl.njabl.org'
    'dnsbl.sorbs.net'
    'drone.abuse.ch'
    'drone.abuse.ch'
    'duinv.aupads.org'
    'dul.dnsbl.sorbs.net'
    'dul.ru'
    'dyna.spamrats.com'
    'dynip.rothen.com'
    'http.dnsbl.sorbs.net'
    'images.rbl.msrbl.net'
    'ips.backscatterer.org'
    'ix.dnsbl.manitu.net'
    'korea.services.net'
    'misc.dnsbl.sorbs.net'
    'noptr.spamrats.com'
    'ohps.dnsbl.net.au'
    'omrs.dnsbl.net.au'
    'orvedb.aupads.org'
    'osps.dnsbl.net.au'
    'osrs.dnsbl.net.au'
    'owfs.dnsbl.net.au'
    'owps.dnsbl.net.au'
    'pbl.spamhaus.org'
    'phishing.rbl.msrbl.net'
    'probes.dnsbl.net.au'
    'proxy.bl.gweep.ca'
    'proxy.block.transip.nl'
    'psbl.surriel.com'
    'rbl.interserver.net'
    'rdts.dnsbl.net.au'
    'relays.bl.gweep.ca'
    'relays.bl.kundenserver.de'
    'relays.nether.net'
    'residential.block.transip.nl'
    'ricn.dnsbl.net.au'
    'rmst.dnsbl.net.au'
    'sbl.spamhaus.org'
    'short.rbl.jp'
    'smtp.dnsbl.sorbs.net'
    'socks.dnsbl.sorbs.net'
    'spam.abuse.ch'
    'spam.dnsbl.sorbs.net'
    'spam.spamrats.com'
    'spamlist.or.kr'
    'spamrbl.imp.ch'
    't3direct.dnsbl.net.au'
    #'tor.ahbl.org' # as per https://ahbl.org/ was terminated in 2015
    'tor.dnsbl.sectoor.de'
    'torserver.tor.dnsbl.sectoor.de'
    'ubl.lashback.com'
    'ubl.unsubscore.com'
    'virbl.bit.nl'
    'virus.rbl.jp'
    'virus.rbl.msrbl.net'
    'web.dnsbl.sorbs.net'
    'wormrbl.imp.ch'
    'xbl.spamhaus.org'
    'zombie.dnsbl.sorbs.net'
)
$Script:ScriptBlockNetDNS = {
    param (
        [string] $Server,
        [string] $IP,
        [bool] $QuickTimeout,
        [bool] $Verbose
    )
    if ($Verbose) {
        $verbosepreference = 'continue'
    }
    $ReversedIP = ($IP -split '\.')[3..0] -join '.'
    $FQDN = "$ReversedIP.$Server"
    try {
        $DnsCheck = [Net.DNS]::GetHostAddresses($fqdn)
    } catch {
        $DnsCheck = $null
    }
    if ($null -ne $DnsCheck) {
        $ServerData = [PSCustomObject] @{
            IP        = $IP
            FQDN      = $FQDN
            BlackList = $Server
            IsListed  = if ($null -eq $DNSCheck.IPAddressToString) { $false } else { $true }
            Answer    = $DnsCheck.IPAddressToString -join ', '
            TTL       = ''
        }
    } else {
        $ServerData = [PSCustomObject] @{
            IP        = $IP
            FQDN      = $FQDN
            BlackList = $Server
            IsListed  = $false
            Answer    = ""
            TTL       = ''
        }
    }

    return $ServerData
}
$Script:ScriptBlockNetDNSSlow = {
    param (
        [string[]] $Servers,
        [string[]] $IPs,
        [bool] $QuickTimeout,
        [bool] $Verbose
    )
    if ($Verbose) {
        $verbosepreference = 'continue'
    }

    $Blacklisted = foreach ($Server in $Servers) {
        foreach ($IP in $IPS) {
            [string] $ReversedIP = ($IP -split '\.')[3..0] -join '.'
            [string] $FQDN = "$ReversedIP.$Server"
            try {
                $DnsCheck = [Net.DNS]::GetHostAddresses($FQDN)
            } catch {
                $DnsCheck = $null
            }
            if ($null -ne $DnsCheck) {
                [PSCustomObject] @{
                    IP        = $ip
                    FQDN      = $fqdn
                    BlackList = $server
                    IsListed  = if ($null -eq $DNSCheck.IPAddressToString) { $false } else { $true }
                    Answer    = $DnsCheck.IPAddressToString -join ', '
                    TTL       = ''
                }
            } else {
                [PSCustomObject] @{
                    IP        = $IP
                    FQDN      = $FQDN
                    BlackList = $Server
                    IsListed  = $false
                    Answer    = ''
                    TTL       = ''
                }
            }
        }
    }
    return $Blacklisted
}
$Script:ScriptBlockResolveDNS = {
    param (
        [string] $Server,
        [string] $IP,
        [bool] $QuickTimeout,
        [bool] $Verbose
    )
    if ($Verbose) {
        $verbosepreference = 'continue'
    }
    [string] $ReversedIP = ($IP -split '\.')[3..0] -join '.'
    [string] $FQDN = "$ReversedIP.$Server"

    [int] $Count = 0
    [bool] $Loaded = $false
    Do {
        try {
            Import-Module -Name 'DnsClient'
            $Loaded = $true
        } catch {
            Write-Warning "DNSClient Import Error ($Server / $FQDN / $IP): $_. Retrying."
        }
        $Count++
        if ($Loaded -eq $false -and $Count -eq 5) {
            Write-Warning "DNSClient Import failed. Skipping check on $Server / $FQDN / $IP"
        }
    } until ($Loaded -eq $false -or $Count -eq 5)
    $DnsCheck = Resolve-DnsName -Name $fqdn -DnsOnly -ErrorAction 'SilentlyContinue' -NoHostsFile -QuickTimeout:$QuickTimeout # Impact of using -QuickTimeout unknown

    if ($null -ne $DnsCheck) {
        $ServerData = [PSCustomObject] @{
            IP        = $IP
            FQDN      = $FQDN
            BlackList = $Server
            IsListed  = if ($null -eq $DNSCheck.IpAddress) { $false } else { $true }
            Answer    = $DnsCheck.IPAddress -join ', '
            TTL       = $DnsCheck.TTL -join ', '
        }
    } else {
        $ServerData = [PSCustomObject]  @{
            IP        = $IP
            FQDN      = $FQDN
            BlackList = $Server
            IsListed  = $false
            Answer    = ''
            TTL       = ''
        }
    }
    return $ServerData
}
$Script:ScriptBlockResolveDNSSlow = {
    param (
        [string[]] $Servers,
        [string[]] $IPs,
        [bool] $QuickTimeout,
        [bool] $Verbose
    )
    if ($Verbose) {
        $verbosepreference = 'continue'
    }
    $Blacklisted = foreach ($Server in $Servers) {
        foreach ($IP in $IPS) {
            $ReversedIP = ($IP -split '\.')[3..0] -join '.'
            $FQDN = "$ReversedIP.$Server"
            $DnsCheck = Resolve-DnsName -Name $fqdn -DnsOnly -ErrorAction 'SilentlyContinue' -NoHostsFile -QuickTimeout:$QuickTimeout # Impact of using -QuickTimeout unknown
            if ($null -ne $DnsCheck) {
                [PSCustomObject] @{
                    IP        = $IP
                    FQDN      = $FQDN
                    BlackList = $Server
                    IsListed  = if ($null -eq $DNSCheck.IpAddress) { $false } else { $true }
                    Answer    = $DnsCheck.IPAddress -join ', '
                    TTL       = $DnsCheck.TTL -join ', '
                }
            } else {
                [PSCustomObject] @{
                    IP        = $IP
                    FQDN      = $FQDN
                    BlackList = $Server
                    IsListed  = $false
                    Answer    = ''
                    TTL       = ''
                }
            }
        }
    }
    return $Blacklisted
}
function Search-BlackList {
    [cmdletbinding()]
    <#
      .SYNOPSIS
      Search-Blacklist searches if particular IP is blacklisted on DNSBL Blacklists.
      .DESCRIPTION
 
      .PARAMETER IPs
 
      .PARAMETER BlacklistServers
 
      .PARAMETER ReturnAll
 
      .PARAMETER RunType
 
      .PARAMETER SortBy
 
      .PARAMETER SortDescending
 
      .EXAMPLE
      Search-BlackList -IP '89.25.253.1' | Format-Table
      Search-BlackList -IP '89.25.253.1' -SortBy Blacklist | Format-Table
      Search-BlackList -IP '89.25.253.1','195.55.55.55' -SortBy Ip -ReturnAll | Format-Table
 
      .NOTES
 
    #>

    param
    (
        [alias('IP')][string[]] $IPs,
        [string[]] $BlacklistServers = $Script:BlackLists,
        [switch] $ReturnAll,
        [ValidateSet('NoWorkflowAndRunSpaceNetDNS', 'NoWorkflowAndRunSpaceResolveDNS', 'RunSpaceWithResolveDNS', 'RunSpaceWithNetDNS', 'WorkflowResolveDNS', 'WorkflowWithNetDNS')][string]$RunType = 'RunSpaceWithResolveDNS',
        [ValidateSet('IP', 'BlackList', 'IsListed', 'Answer', 'FQDN')][string] $SortBy = 'IsListed',
        [switch] $SortDescending,
        [switch] $QuickTimeout,
        [int] $MaxRunspaces = 40,
        [switch] $ExtendedOutput
    )
    if ($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent) { $Verbose = $true } else { $Verbose = $false }

    # will remove this after a while
    if ($RunType -eq 'WorkflowResolveDNS') {
        Write-Warning 'Worflows are not supported anymore due to PowerShell 6 complaining. Please use other modes.'
        Exit
    } elseif ($RunType -eq 'WorkflowWithNetDNS') {
        Write-Warning 'Worflows are not supported anymore due to PowerShell 6 complaining. Please use other modes.'
        Exit
    }

    if ($PSVersionTable.Platform -eq 'Unix') {
        if ($RunType -eq 'RunSpaceWithResolveDNS') {
            $RunType = 'RunSpaceWithNetDNS'
            Write-Warning 'Search-BlackList - changing RunType to RunSpaceWithNetDNS since Resolve-DNSName is not available on Linux/MacOS'
        } elseif ($RunType -eq 'NoWorkflowAndRunSpaceResolveDNS') {
            $RunType = 'NoWorkflowAndRunSpaceNetDNS'
            Write-Warning 'Search-BlackList - changing RunType to RunSpaceWithNetDNS since Resolve-DNSName is not available on Linux/MacOS'
        }
    }


    If ($RunType -eq 'NoWorkflowAndRunSpaceNetDNS') {
        $Table = Invoke-Command -ScriptBlock $Script:ScriptBlockNetDNSSlow -ArgumentList $BlacklistServers, $IPs, $QuickTimeout, $Verbose
    } elseif ($RunType -eq 'NoWorkflowAndRunSpaceResolveDNS') {
        $Table = Invoke-Command -ScriptBlock $Script:ScriptBlockResolveDNSSlow -ArgumentList $BlacklistServers, $IPs, $QuickTimeout, $Verbose
    } elseif ($RunType -eq 'RunSpaceWithResolveDNS') {
        ### Define Runspace START
        $pool = New-Runspace -MaxRunspaces $maxRunspaces -Verbose:$Verbose
        ### Define Runspace END
        $runspaces = foreach ($Server in $BlacklistServers) {
            foreach ($IP in $IPs) {
                $Parameters = @{
                    Server       = $Server
                    IP           = $IP
                    QuickTimeout = $QuickTimeout
                    Verbose      = $Verbose
                }
                Start-Runspace -ScriptBlock $Script:ScriptBlockResolveDNS -Parameters $Parameters -RunspacePool $pool -Verbose:$Verbose
            }
        }
        ### End Runspaces START
        $Output = Stop-Runspace -Runspaces $runspaces -FunctionName 'Search-BlackList' -RunspacePool $pool -Verbose:$Verbose -ErrorAction Continue -ErrorVariable MyErrors -ExtendedOutput:$ExtendedOutput
        if ($ExtendedOutput) {
            $Output # returns hashtable of Errors and Output
            Exit
        } else {
            $Table = $Output
        }
        ### End Runspaces END

    } elseif ($RunType -eq 'RunSpaceWithNetDNS') {
        ### Define Runspace START
        $pool = New-Runspace -MaxRunspaces $maxRunspaces -Verbose:$Verbose
        ### Define Runspace END
        $runspaces = foreach ($server in $BlacklistServers) {
            foreach ($ip in $IPs) {
                $Parameters = @{
                    Server       = $Server
                    IP           = $IP
                    QuickTimeout = $QuickTimeout
                    Verbose      = $Verbose
                }
                Start-Runspace -ScriptBlock $Script:ScriptBlockNetDNS -Parameters $Parameters -RunspacePool $pool -Verbose:$Verbose
            }
        }
        ### End Runspaces START
        $Output = Stop-Runspace -Runspaces $runspaces -FunctionName 'Search-BlackList' -RunspacePool $pool -Verbose:$Verbose -ExtendedOutput:$ExtendedOutput
        if ($ExtendedOutput) {
            $Output # returns hashtable of Errors and Output
            Exit
        } else {
            $Table = $Output
        }
        ### End Runspaces END
    }
    if ($SortDescending -eq $true) {
        $Table = $Table | Sort-Object $SortBy -Descending
    } else {
        $Table = $Table | Sort-Object $SortBy
    }
    if ($ReturnAll -eq $true) {
        return $Table | Select-Object IP, FQDN, BlackList, IsListed, Answer, TTL
    } else {
        return $Table | Where-Object { $_.IsListed -eq $true } | Select-Object IP, FQDN, BlackList, IsListed, Answer, TTL
    }
}
function Set-EmailBody($TableData, $TableWelcomeMessage) {
    $body = "<p><i>$TableWelcomeMessage</i>"
    if ($($TableData | Measure-Object).Count -gt 0) {
        $body += $TableData | ConvertTo-Html -Fragment | Out-String
        $body = $body -replace ' Added', "<font color=`"green`"><b> Added</b></font>"
        $body = $body -replace ' Removed', "<font color=`"red`"><b> Removed</b></font>"
        $body = $body -replace ' Deleted', "<font color=`"red`"><b> Deleted</b></font>"
        $body = $body -replace ' Changed', "<font color=`"blue`"><b> Changed</b></font>"
        $body = $body -replace ' Change', "<font color=`"blue`"><b> Change</b></font>"
        $body = $body -replace ' Disabled', "<font color=`"red`"><b> Disabled</b></font>"
        $body = $body -replace ' Enabled', "<font color=`"green`"><b> Enabled</b></font>"
        $body = $body -replace ' Locked out', "<font color=`"red`"><b> Locked out</b></font>"
        $body = $body -replace ' Lockouts', "<font color=`"red`"><b> Lockouts</b></font>"
        $body = $body -replace ' Unlocked', "<font color=`"green`"><b> Unlocked</b></font>"
        $body = $body -replace ' Reset', "<font color=`"blue`"><b> Reset</b></font>"
        $body += '</p>'
    } else {
        $body += '<br><i>No changes happend during that period.</i></p>'
    }
    return $body
}
function Set-EmailReportDetails {
    param(
        $FormattingOptions,
        $ReportOptions,
        $TimeToGenerate
    )
    $DateReport = get-date
    # HTML Report settings
    $Report = "<p style=`"background-color:white;font-family:$($FormattingOptions.FontFamily);font-size:$($FormattingOptions.FontSize)`">"
    $Report += "<strong>Report Time:</strong> $DateReport <br>"
    $Report += "<strong>Time to generate:</strong> $($TimeToGenerate.Hours) hours, $($TimeToGenerate.Minutes) minutes, $($TimeToGenerate.Seconds) seconds, $($TimeToGenerate.Milliseconds) milliseconds <br>"

    if ($PSVersionTable.Platform -ne 'Unix') {
        $Report += "<strong>Account Executing Report :</strong> $env:userdomain\$($env:username.toupper()) on $($env:ComputerName.toUpper()) <br>"
    } else {
        # needs filling in.
    }
    $Report += '<strong>Checking for monitored IPs :</strong>'
    $Report += '<ul>'
    foreach ($ip in $ReportOptions.MonitoredIps.Values) {
        $Report += "<li>ip:</strong> $ip</li>"
    }
    $Report += '</ul>'
    $Report += '</p>'
    return $Report
}
function Start-ReportBlackLists {
    [cmdletbinding()]
    param(
        $EmailParameters,
        $FormattingParameters,
        $ReportOptions,
        [switch] $OutputErrors
    )
    $Errors = @{
        Teams   = $false
        Slack   = $false
        Discord = $false
    }
    $EmailBody = Set-EmailHead -FormattingOptions $FormattingParameters
    $EmailBody += Set-EmailReportBranding -FormattingOptions $FormattingParameters


    $TeamID = Format-FirstXChars -Text $ReportOptions.NotificationsTeams.TeamsID -NumberChars 25
    $SlackID = Format-FirstXChars -Text $ReportOptions.NotificationsSlack.Uri -NumberChars 25
    $DiscordID = Format-FirstXChars -Text $ReportOptions.NotificationsDiscord.Uri -NumberChars 25

    Write-Verbose "Start-ReportBlackLists - TeamsID: $TeamID"
    Write-Verbose "Start-ReportBlackLists - SlackID: $SlackID"
    Write-Verbose "Start-ReportBlackLists - DiscordID: $DiscordID"

    $Ips = @()
    foreach ($ip in $ReportOptions.MonitoredIps.Values) {
        $Ips += $ip
    }
    $Time = Measure-Command -Expression {
        if ($null -eq $ReportOptions.SortBy) {
            $ReportOptions.SortBy = 'IsListed'
        }
        if ($null -eq $ReportOptions.SortDescending) {
            $ReportOptions.SortDescending = $true
        }

        if ($ReportOptions.NotificationsEmail.EmailAllResults) {
            $BlackListCheck = Search-BlackList -IP $Ips -SortBy $ReportOptions.SortBy -SortDescending:$ReportOptions.SortDescending -ReturnAll
        } else {
            $BlackListCheck = Search-BlackList -IP $Ips -SortBy $ReportOptions.SortBy -SortDescending:$ReportOptions.SortDescending
        }
    }
    $EmailBody += Set-EmailReportDetails -FormattingOptions $FormattingParameters -ReportOptions $ReportOptions -TimeToGenerate $Time
    $EmailBody += Set-EmailBody -TableData $BlackListCheck -TableWelcomeMessage 'Following blacklisted servers'

    if ($null -eq $ReportOptions.NotificationsEmail) {
        # Not upgraded config / Legacy config
        $ReportOptions.NotificationsEmail = @{
            Use                          = $true
            EmailPriorityWhenBlacklisted = $ReportOptions.EmailPriorityWhenBlacklisted
            EmailPriorityStandard        = $ReportOptions.EmailPriorityStandard
            EmailAllResults              = $ReportOptions.EmailAllResults
            EmailAlways                  = $ReportOptions.EmailAlways
        }
    }

    if ($BlackListCheck.IsListed -contains $true) {
        $EmailParameters.EmailPriority = $ReportOptions.NotificationsEmail.EmailPriorityWhenBlacklisted
    } else {
        $EmailParameters.EmailPriority = $ReportOptions.NotificationsEmail.EmailPriorityStandard
    }


    if ($ReportOptions.NotificationsEmail.Use) {
        if ($ReportOptions.EmailAlways -eq $true -or $BlackListCheck.IsListed -contains $true) {
            if ($FormattingParameters.CompanyBranding.Inline) {
                $SendMail = Send-Email -EmailParameters $EmailParameters -Body $EmailBody -InlineAttachments @{logo = $FormattingParameters.CompanyBranding.Logo} -Verbose
            } else {
                $SendMail = Send-Email -EmailParameters $EmailParameters -Body $EmailBody
            }
        }
    }

    if ($BlackListCheck.IsListed -contains $true) {
        $BlackListLimited = $BlackListCheck | Where-Object { $_.IsListed -eq $true }

        if ($ReportOptions.NotificationsTeams.Use) {
            [string] $MessageTitle = $ReportOptions.NotificationsTeams.MessageTitle
            [string] $ActivityImageLink = $ReportOptions.NotificationsTeams.MessageImageLink

            [RGBColors] $Color = [RGBColors]::Red
            $Sections = @()
            foreach ($Server in $BlackListLimited) {
                [string] $ActivityTitle = "Blacklisted IP **$($Server.IP)**"
                if ($ReportOptions.NotificationsTeams.MessageButtons) {
                    $Button1 = New-TeamsButton -Name "Check BlackList" -Link "https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a$($Server.Ip)&run=toolpage"
                    $Button2 = New-TeamsButton -Name "Check SMTP" -Link "https://mxtoolbox.com/SuperTool.aspx?action=smtp%3a$($Server.Ip)&run=toolpage"

                    $Sections += New-TeamsSection `
                        -ActivityTitle $ActivityTitle `
                        -ActivitySubtitle "Found on blacklist **$($Server.Blacklist)**" `
                        -ActivityImageLink $ActivityImageLink `
                        -ActivityText "Everybody panic!" `
                        -Buttons $Button1, $Button2
                } else {
                    $Sections += New-TeamsSection `
                        -ActivityTitle $ActivityTitle `
                        -ActivitySubtitle "Found on blacklist **$($Server.Blacklist)**" `
                        -ActivityImageLink $ActivityImageLink `
                        -ActivityText "Responses: $($Server.Answer)"
                }
            }

            try {
                $TeamsOutput = Send-TeamsMessage `
                    -URI $ReportOptions.NotificationsTeams.TeamsID `
                    -MessageTitle $MessageTitle `
                    -Color $Color `
                    -Sections $Sections `
                    -Supress $false
            } catch {
                $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
                Write-Warning "Couldn't send to Teams - Error occured: $ErrorMessage"
                $Errors.Teams = $true
            }
            #Write-Color @script:WriteParameters -Text "[i] Teams output: ", $Data -Color White, Yellow
        }
        if ($ReportOptions.NotificationsSlack.Use) {

            $MessageTitle = $ReportOptions.NotificationsSlack.MessageTitle
            [string] $ActivityImageLink = $ReportOptions.NotificationsSlack.MessageImageLink

            $Attachments = @()
            foreach ($Server in $BlackListLimited) {
                $Attachments += New-SlackMessageAttachment -Color $_PSSlackColorMap.red `
                    -Title "IP $($Server.IP) is Blacklisted" `
                    -TitleLink "https://mxtoolbox.com/SuperTool.aspx?action=blacklist%3a$($Server.Ip)&run=toolpage" `
                    -Text $ReportOptions.NotificationsSlack.MessageText `
                    -Pretext "Found on blacklist $($Server.Blacklist)" `
                    -Fallback 'Your client is bad'
            }

            try {
                $SlackOutput = New-SlackMessage -Attachments $Attachments `
                    -Channel $ReportOptions.NotificationsSlack.Channel `
                    -IconEmoji $ReportOptions.NotificationsSlack.MessageEmoji `
                    -AsUser `
                    -Username $ReportOptions.NotificationsSlack.MessageAsUser | `
                    Send-SlackMessage -Uri $ReportOptions.NotificationsSlack.URI
            } catch {
                $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
                Write-Warning "Couldn't send to Slack - Error occured: $ErrorMessage"
                $Errors.Slack = $true
            }
            #Write-Color @script:WriteParameters -Text "[i] Slack output: ", $Data -Color White, Yellow
        }

        if ($ReportOptions.NotificationsDiscord.Use) {
            if ($null -eq $ReportOptions.NotificationsDiscord.MessageInline) {
                $ReportOptions.NotificationsDiscord.MessageInline = $false
            }

            try {
                $Facts = foreach ($Server in $BlackListLimited) {
                    [string] $ActivityTitle = "Blacklisted IP $($Server.IP)"
                    [string] $ActivityValue = "Found on blacklist $($Server.Blacklist)"

                    New-DiscordFact -Name $ActivityTitle -Value $ActivityValue -Inline $ReportOptions.NotificationsDiscord.MessageInline
                }

                $Thumbnail = New-DiscordThumbnail -Url $ReportOptions.NotificationsDiscord.MessageImageLink
                $Author = New-DiscordAuthor -Name 'PSBlacklistChecker' -IconUrl  $ReportOptions.NotificationsDiscord.MessageImageLink
                $Section = New-DiscordSection -Title $ReportOptions.NotificationsDiscord.MessageText `
                    -Description '' `
                    -Facts $Facts `
                    -Color $ReportOptions.NotificationsDiscord.MessageColor `
                    -Author $Author `
                    -Thumbnail $Thumbnail #-Image $Thumbnail

                Send-DiscordMessage -WebHookUrl $ReportOptions.NotificationsDiscord.Uri `
                    -Sections $Section `
                    -AvatarName $ReportOptions.NotificationsDiscord.MessageAsUser `
                    -AvatarUrl $ReportOptions.NotificationsDiscord.MessageAsUserImage -Verbose

            } catch {
                $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
                Write-Warning "Couldn't send to Discord - Error occured: $ErrorMessage"
                $Errors.Discord = $true
            }
        }
        if ($OutputErrors) {
            return $Errors
        }
    }
}


Export-ModuleMember `
    -Function @('Search-BlackList','Start-ReportBlackLists') `
    -Alias @('')