CheckSec.psm1
function checkDomain { param ( [Parameter(Mandatory)] [string] $Domain ) # Checking whether domain exists try { Resolve-DnsName $Domain -NoHostsFile -DnsOnly -ErrorAction stop | out-null } catch { Write-error "`n$_" Break } # Checking for an MX record $mxCheck = Resolve-DnsName $Domain -type MX -ErrorAction SilentlyContinue if (($mxCheck) -and ($mxCheck.type -eq "MX")) { $mxCheck = $true } else { $mxCheck = $false } $result = [PSCustomObject]@{ MX = $mxCheck } return $result } function Test-SpfRecord { [CmdletBinding()] param ( [parameter(Position = 0, ValueFromPipeline=$true)] [string] $SPF, [parameter()] [string] $Domain ) if ($Domain) { $SPF = (Resolve-DnsName $Domain -Type TXT -ErrorAction SilentlyContinue | Where-Object -Property Strings -Like "v=spf1*" | Select-Object -ExpandProperty Strings).replace("{}", "").substring(7) } # Creating array list for any include that is found in the SPF record $spfIncludeList = New-Object System.Collections.Generic.List[System.Object] # Split the SPF, create the counting variables and check every single mechanism $spfSplit = $SPF.split(" ") $spfCountInclude = $null $spfCountA = $null $spfCountPtr = $null $spfCountMX = $null $spfCountExists = $null foreach ($spfMechanism in $spfSplit) { if ($spfMechanism -like "include:*") { $spfIncludeList.add($spfMechanism.Trim("include:")) $spfCountInclude += 1 } elseif ($spfMechanism -like "a:*") { $spfCountA += 1 } elseif ($spfMechanism -like "ptr:*") { $spfCountPtr += 1 Write-Warning $spfMechanism } elseif ($spfMechanism -like "mx:*") { $spfCountMX += 1 } elseif ($spfMechanism -like "exists:*") { $spfCountExists += 1 } # Warning about PTR if ($spfPtr) { } # All mechanism, qualifier? if ($spfMechanism -like "*all") { $spfAllQualifier = $spfMechanism.trim("all") } } # Total count of mechanisms that triggers DNS lookups $spfTotalLookups = ($spfCountInclude + $spfCountA + $spfCountPtr + $spfCountMX + $spfCountExists) # Create a PSCustomObject and return it as the result $result = [PSCustomObject]@{ 'TotalLookups' = $spfTotalLookups 'includes' = $spfCountInclude 'a' = $spfCountA 'ptr' = $spfCountPtr 'mx' = $spfCountMX 'exists' = $spfCountExists 'All' = $spfAllQualifier 'includeList' = $spfIncludeList } $result.psobject.TypeNames.Insert(0, "Test-SpfRecord") return $result } function Test-EmailSecurity { param ( [Parameter(Position = 0, Mandatory)] [string] $Domain ) # Check whether domain exists & check if there is an MX and set it accordingly $checkDomain = checkDomain $Domain if ($checkDomain.MX) { $domainMX = (Resolve-DnsName $Domain -Type MX -ErrorAction SilentlyContinue | Select-Object -ExpandProperty NameExchange -first 1 -ErrorAction SilentlyContinue).toLower() } $domainSPF = (Resolve-DnsName $Domain -Type TXT -ErrorAction SilentlyContinue | Where-Object -Property Strings -Like "v=spf1*" | Select-Object -ExpandProperty Strings) $domainDmarc = (Resolve-DnsName "_dmarc.$Domain" -type TXT -ErrorAction SilentlyContinue) # SPF $spfTotalLookups = $null if (!$domainSPF) { $spfPresent = $false $spfList = $null } else { $spfPresent = $true [System.Collections.ArrayList]$spfList = @() $spfList.add($domain) | Out-Null do { if ($spfList) { $spfValue = (Resolve-DnsName $spfList[0] -Type TXT -ErrorAction SilentlyContinue | Where-Object -Property Strings -Like "v=spf1*" | Select-Object -ExpandProperty Strings).replace("{}", "").substring(7) $spfList.RemoveAt(0) | Out-Null } $spfTest = Test-SpfRecord $spfValue.ToString() $spfList += $spfTest.includeList $spfTotalLookups += $spfTest.TotalLookups if ($spfTest.ptr) { $spfPtr = $true Write-Warning "Using the PTR mechanism is not recommended!" Write-Warning "Reference: RFC7208 Section 5.5." } else { $spfPtr = $false } } while ($spfList) } # DKIM if (($domainMX -like "*outlook.com") -or ($domainSPF -like "*outlook.com*") ) { # Exchange Online uses selector1 and selector2._domainkey $dkimCheck = Resolve-DnsName selector1._domainkey.$domain -DnsOnly -ErrorAction SilentlyContinue if ($dkimCheck) { $dkimPresent = $true } else { $dkimPresent = $false } } if ($domainMX -like "*google.com") { # G suite uses google._domainkey $dkimCheck = Resolve-DnsName google._domainkey.$domain -DnsOnly -ErrorAction SilentlyContinue if ($dkimCheck) { $dkimPresent = $true } else { $dkimPresent = $false } } if ($domainMX -eq "mail.protonmail.ch") { $dkimCheck = Resolve-DnsName protonmail._domainkey.$domain -DnsOnly -ErrorAction SilentlyContinue if ($dkimCheck) { $dkimPresent = $true } else { $dkimPresent = $false } } # DMARC if ($domainDmarc) { $domainDmarcPresent = $true } else { $domainDmarcPresent = $false } if ($domainDmarc.strings -like "*p=reject*") { $dmarcPolicy = "reject" } elseif ($domainDmarc.strings -like "*p=quarantine*") { $dmarcPolicy = "quarantine" } elseif ($domainDmarc.strings -like "*p=none*") { $dmarcPolicy = "none" } else { $dmarcPolicy = "N/A" } # Make a custom object with the results $result = [PSCustomObject]@{ 'Domain' = $Domain 'MX' = $domainMX 'SpfPresent' = $spfPresent 'SpfRecord' = $domainSPF 'SpfDnsMechanism' = $spfTotalLookups 'SpfPtrInUse' = $SpfPtr 'DkimPresent' = $dkimPresent 'DmarcPresent' = $domainDmarcPresent 'DmarcPolicy' = $dmarcPolicy } if ($result.SpfDnsMechanism -gt 10) { Write-Warning "More than 10 DNS lookups will result in PermError, this SPF is currently doing $spfTotalLookups!" Write-Warning "Reference: RFC7208 Section 4.6.4." } return $result } |