PowerShell Arsenal
Battle-tested scripts for enterprise automation
Bulk Email Security Auditor
This PowerShell script analyzes email domains for security vulnerabilities and generates personalized sales outreach messages. It takes a CSV list of email addresses, checks each domains SPF, DKIM, and DMARC security records, then creates customized cold outreach emails that sales professionals can use to contact prospects.
Key Features:
Automated Security Analysis: Scans domains for email authentication records (SPF, DKIM, DMARC)
User-Friendly Results: Outputs easy-to-read CSV with security scores and ratings
Sales-Ready Outreach: Generates personalized cold email messages based on specific security gaps found
Business Value Focus: Translates technical findings into business impact (deliverability issues, spam problems)
Perfect For:
Sales professionals prospecting email service companies
Email marketing agencies identifying potential clients
IT consultants demonstrating expertise to prospects
Anyone wanting to lead sales conversations with technical credibility
Input: CSV with email addresses
Output: Comprehensive analysis + ready-to-send personalized sales messages
Essentially, it turns technical email security analysis into a powerful lead generation and sales prospecting tool that demonstrates immediate value to potential customers.
# ================================================================================
# Bulk Email Security Auditor
# Developer: Aaron Kinder
# Description: Advanced tool for analyzing email domains and their security posture
# Version: 1.0
# ================================================================================
# Global configuration
$Global:InputFileName = "input_email_list.csv"
$Global:OutputFileName = "output_security_list.csv"
$Global:DnsTimeoutSeconds = 8
$Global:MaxConcurrentJobs = 10
$Global:DomainCache = @{}
function Show-AsciiArtBanner {
Clear-Host
Write-Host @"
╔══════════════════════════════════════════════════════════════════════════════╗
║ ║
║ ██████╗ ██╗ ██╗██╗ ██╗ ██╗ ███████╗███╗ ███╗ █████╗ ██╗██╗ ║
║ ██╔══██╗██║ ██║██║ ██║ ██╔╝ ██╔════╝████╗ ████║██╔══██╗██║██║ ║
║ ██████╔╝██║ ██║██║ █████╔╝ █████╗ ██╔████╔██║███████║██║██║ ║
║ ██╔══██╗██║ ██║██║ ██╔═██╗ ██╔══╝ ██║╚██╔╝██║██╔══██║██║██║ ║
║ ██████╔╝╚██████╔╝███████╗██║ ██╗ ███████╗██║ ╚═╝ ██║██║ ██║██║███████╗ ║
║ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝ ║
║ ║
║ ███████╗███████╗ ██████╗██╗ ██╗██████╗ ██╗████████╗██╗ ██╗ ║
║ ███████╗██╔════╝██╔════╝██║ ██║██╔══██╗██║╚══██╔══╝╚██╗ ██╔╝ ║
║ ╚════██║█████╗ ██║ ██║ ██║██████╔╝██║ ██║ ╚████╔╝ ║
║ ██║██╔══╝ ██║ ██║ ██║██╔══██╗██║ ██║ ╚██╔╝ ║
║ ███████║███████╗╚██████╗╚██████╔╝██║ ██║██║ ██║ ██║ ║
║ ╚══════╝╚══════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ║
║ ║
║ █████╗ ██╗ ██╗██████╗ ██╗████████╗ ██████╗ ██████╗ ║
║ ██╔══██╗██║ ██║██╔══██╗██║╚══██╔══╝██╔═══██╗██╔══██╗ ║
║ ███████║██║ ██║██║ ██║██║ ██║ ██║ ██║██████╔╝ ║
║ ██╔══██║██║ ██║██║ ██║██║ ██║ ██║ ██║██╔══██╗ ║
║ ██║ ██║╚██████╔╝██████╔╝██║ ██║ ╚██████╔╝██║ ██║ ║
║ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ║
║ ║
║ Developed by: Aaron Kinder ║
║ Version 1.0 ║
╚══════════════════════════════════════════════════════════════════════════════╝
"@ -ForegroundColor Cyan
Write-Host ""
}
function Show-MainNavigationMenu {
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor White
Write-Host "│ MAIN MENU OPTIONS │" -ForegroundColor White
Write-Host "├────────────────────────────────────────────────────────────────────────────┤" -ForegroundColor White
Write-Host "│ │" -ForegroundColor White
Write-Host "│ [1] 🔍 Complete Email Security Analysis │" -ForegroundColor Green
Write-Host "│ [2] ⚡ Quick Test (First 5 Domains) │" -ForegroundColor Yellow
Write-Host "│ [3] 🎯 Single Domain Analysis │" -ForegroundColor Cyan
Write-Host "│ [4] 📋 View Email Provider Information │" -ForegroundColor Blue
Write-Host "│ [5] 🛡️ View Email Security Standards Guide │" -ForegroundColor Magenta
Write-Host "│ [6] ⚙️ System Configuration & Requirements │" -ForegroundColor DarkCyan
Write-Host "│ [7] ❌ Exit Application │" -ForegroundColor Red
Write-Host "│ │" -ForegroundColor White
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor White
Write-Host ""
}
function Invoke-OptimizedDnsQuery {
param(
[string]$DomainName,
[string]$RecordType,
[int]$TimeoutInSeconds = $Global:DnsTimeoutSeconds
)
$asyncJob = Start-Job -ScriptBlock {
param($Domain, $Type)
try {
$dnsResult = Resolve-DnsName -Name $Domain -Type $Type -ErrorAction Stop
return @{
Success = $true
Data = $dnsResult
Error = $null
}
}
catch {
return @{
Success = $false
Data = $null
Error = $_.Exception.Message
}
}
} -ArgumentList $DomainName, $RecordType
try {
$jobResult = Wait-Job -Job $asyncJob -Timeout $TimeoutInSeconds -ErrorAction SilentlyContinue
if ($jobResult) {
$queryOutput = Receive-Job -Job $asyncJob -ErrorAction SilentlyContinue
Remove-Job -Job $asyncJob -Force -ErrorAction SilentlyContinue
return $queryOutput
} else {
Remove-Job -Job $asyncJob -Force -ErrorAction SilentlyContinue
return @{
Success = $false
Data = $null
Error = "DNS query timeout after $TimeoutInSeconds seconds"
}
}
}
catch {
Remove-Job -Job $asyncJob -Force -ErrorAction SilentlyContinue
return @{
Success = $false
Data = $null
Error = $_.Exception.Message
}
}
}
function Get-EmailProviderFromMxRecords {
param(
[string]$DomainName
)
# Check cache first for performance
if ($Global:DomainCache.ContainsKey("$DomainName-MX")) {
return $Global:DomainCache["$DomainName-MX"]
}
Write-Host " → Analyzing MX records for: $DomainName" -ForegroundColor DarkGray
$mxQueryResult = Invoke-OptimizedDnsQuery -DomainName $DomainName -RecordType "MX"
if (-not $mxQueryResult.Success) {
$errorResult = if ($mxQueryResult.Error -like "*timeout*") { "DNS_TIMEOUT" } else { "DNS_RESOLUTION_FAILED" }
$Global:DomainCache["$DomainName-MX"] = $errorResult
return $errorResult
}
if (-not $mxQueryResult.Data) {
$Global:DomainCache["$DomainName-MX"] = "NO_MX_RECORDS"
return "NO_MX_RECORDS"
}
$mxHostnames = $mxQueryResult.Data | Where-Object { $_.Type -eq "MX" } | ForEach-Object { $_.NameExchange.ToLower() }
if (-not $mxHostnames) {
$Global:DomainCache["$DomainName-MX"] = "NO_MX_RECORDS"
return "NO_MX_RECORDS"
}
# Google Workspace / Gmail MX patterns
$googleMxPatterns = @(
"aspmx.l.google.com",
"alt1.aspmx.l.google.com", "alt2.aspmx.l.google.com",
"alt3.aspmx.l.google.com", "alt4.aspmx.l.google.com",
"gmail-smtp-in.l.google.com", "googlemail.com"
)
# Microsoft 365 / Outlook MX patterns
$microsoftMxPatterns = @(
".mail.protection.outlook.com", ".outlook.com",
"outlook.office365.com", ".onmicrosoft.com",
"mx1.hotmail.com", "mx2.hotmail.com", "mx3.hotmail.com", "mx4.hotmail.com"
)
# Check for Google services
foreach ($mxRecord in $mxHostnames) {
foreach ($googlePattern in $googleMxPatterns) {
if ($mxRecord -like "*$googlePattern*" -or $mxRecord -eq $googlePattern) {
$Global:DomainCache["$DomainName-MX"] = "Google"
return "Google"
}
}
}
# Check for Microsoft services
foreach ($mxRecord in $mxHostnames) {
foreach ($microsoftPattern in $microsoftMxPatterns) {
if ($mxRecord -like "*$microsoftPattern*" -or $mxRecord -eq $microsoftPattern) {
$Global:DomainCache["$DomainName-MX"] = "Microsoft"
return "Microsoft"
}
}
}
# Return concatenated MX records for other providers
$otherProviderResult = ($mxHostnames -join "; ")
$Global:DomainCache["$DomainName-MX"] = $otherProviderResult
return $otherProviderResult
}
function Test-SpfRecordPresence {
param(
[string]$DomainName
)
# Check cache first
if ($Global:DomainCache.ContainsKey("$DomainName-SPF")) {
return $Global:DomainCache["$DomainName-SPF"]
}
$txtQueryResult = Invoke-OptimizedDnsQuery -DomainName $DomainName -RecordType "TXT"
if (-not $txtQueryResult.Success) {
$errorResult = if ($txtQueryResult.Error -like "*timeout*") { "DNS_TIMEOUT" } else { "DNS_ERROR" }
$Global:DomainCache["$DomainName-SPF"] = $errorResult
return $errorResult
}
foreach ($txtRecord in $txtQueryResult.Data) {
if ($txtRecord.Type -eq "TXT" -and $txtRecord.Strings -match "^v=spf1") {
$Global:DomainCache["$DomainName-SPF"] = "PRESENT"
return "PRESENT"
}
}
$Global:DomainCache["$DomainName-SPF"] = "NOT_FOUND"
return "NOT_FOUND"
}
function Test-DkimRecordPresence {
param(
[string]$DomainName
)
# Check cache first
if ($Global:DomainCache.ContainsKey("$DomainName-DKIM")) {
return $Global:DomainCache["$DomainName-DKIM"]
}
# Prioritized DKIM selectors (most common first for efficiency)
$commonDkimSelectors = @("default", "selector1", "selector2", "google", "k1", "s1", "s2")
$discoveredSelectors = @()
foreach ($dkimSelector in $commonDkimSelectors) {
$dkimSubdomain = "$dkimSelector._domainkey.$DomainName"
$dkimQueryResult = Invoke-OptimizedDnsQuery -DomainName $dkimSubdomain -RecordType "TXT"
if (-not $dkimQueryResult.Success) {
if ($dkimQueryResult.Error -like "*timeout*") {
$Global:DomainCache["$DomainName-DKIM"] = "DNS_TIMEOUT"
return "DNS_TIMEOUT"
}
continue # Try next selector
}
foreach ($txtRecord in $dkimQueryResult.Data) {
if ($txtRecord.Type -eq "TXT" -and $txtRecord.Strings -match "v=DKIM1") {
$discoveredSelectors += $dkimSelector
break
}
}
# Early exit if we found one (saves time)
if ($discoveredSelectors.Count -gt 0) {
break
}
}
if ($discoveredSelectors.Count -gt 0) {
$result = "PRESENT ($($discoveredSelectors -join ', 039;))"
$Global:DomainCache["$DomainName-DKIM"] = $result
return $result
} else {
$Global:DomainCache["$DomainName-DKIM"] = "NOT_FOUND"
return "NOT_FOUND"
}
}
function Test-DmarcRecordPresence {
param(
[string]$DomainName
)
# Check cache first
if ($Global:DomainCache.ContainsKey("$DomainName-DMARC")) {
return $Global:DomainCache["$DomainName-DMARC"]
}
$dmarcSubdomain = "_dmarc.$DomainName"
$dmarcQueryResult = Invoke-OptimizedDnsQuery -DomainName $dmarcSubdomain -RecordType "TXT"
if (-not $dmarcQueryResult.Success) {
$errorResult = if ($dmarcQueryResult.Error -like "*timeout*") { "DNS_TIMEOUT" } else { "DNS_ERROR" }
$Global:DomainCache["$DomainName-DMARC"] = $errorResult
return $errorResult
}
foreach ($txtRecord in $dmarcQueryResult.Data) {
if ($txtRecord.Type -eq "TXT" -and $txtRecord.Strings -match "v=DMARC1") {
$dmarcRecordContent = $txtRecord.Strings -join ""
# Parse DMARC policy
if ($dmarcRecordContent -match "p=reject") {
$result = "PRESENT_REJECT"
$Global:DomainCache["$DomainName-DMARC"] = $result
return $result
}
elseif ($dmarcRecordContent -match "p=quarantine") {
$result = "PRESENT_QUARANTINE"
$Global:DomainCache["$DomainName-DMARC"] = $result
return $result
}
elseif ($dmarcRecordContent -match "p=none") {
$result = "PRESENT_NONE"
$Global:DomainCache["$DomainName-DMARC"] = $result
return $result
}
else {
$result = "PRESENT_UNCLEAR"
$Global:DomainCache["$DomainName-DMARC"] = $result
return $result
}
}
}
$Global:DomainCache["$DomainName-DMARC"] = "NOT_FOUND"
return "NOT_FOUND"
}
function Extract-DomainFromEmailAddress {
param(
[string]$EmailAddress
)
if ($EmailAddress -match "@(.+)$") {
return $matches[1].Trim().ToLower()
} else {
return $null
}
}
function Test-IndividualDomainSecurity {
Write-Host ""
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor Cyan
Write-Host "│ SINGLE DOMAIN ANALYSIS │" -ForegroundColor Cyan
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor Cyan
Write-Host ""
$domainToTest = Read-Host "Enter domain name to analyze (e.g., example.com)"
if ([string]::IsNullOrWhiteSpace($domainToTest)) {
Write-Host "❌ Invalid domain entered." -ForegroundColor Red
return
}
# Clean domain input
$domainToTest = $domainToTest -replace "^https?://", "" -replace "^www\.", ""
Write-Host ""
Write-Host "🔍 Analyzing domain: $domainToTest" -ForegroundColor Cyan
Write-Host "═══════════════════════════════════════════════════════════════════════════════" -ForegroundColor Cyan
# Email provider analysis
$emailProvider = Get-EmailProviderFromMxRecords -DomainName $domainToTest
Write-Host ""
Write-Host "📧 EMAIL PROVIDER:" -NoNewline -ForegroundColor White
switch ($emailProvider) {
"Google" { Write-Host " $emailProvider" -ForegroundColor Green }
"Microsoft" { Write-Host " $emailProvider" -ForegroundColor Blue }
"DNS_TIMEOUT" { Write-Host " DNS Timeout" -ForegroundColor Red }
"DNS_RESOLUTION_FAILED" { Write-Host " DNS Resolution Failed" -ForegroundColor Red }
"NO_MX_RECORDS" { Write-Host " No MX Records Found" -ForegroundColor Yellow }
default { Write-Host " $emailProvider" -ForegroundColor Magenta }
}
# Security records analysis
Write-Host ""
Write-Host "🛡️ EMAIL SECURITY ANALYSIS:" -ForegroundColor White
Write-Host "────────────────────────────────────────────────────────────────────────────────" -ForegroundColor Gray
Write-Host " SPF Record: " -NoNewline -ForegroundColor White
$spfStatus = Test-SpfRecordPresence -DomainName $domainToTest
switch ($spfStatus) {
"PRESENT" { Write-Host "✅ Present" -ForegroundColor Green }
"DNS_TIMEOUT" { Write-Host "⏱️ DNS Timeout" -ForegroundColor Red }
default { Write-Host "❌ Not Found" -ForegroundColor Red }
}
Write-Host " DKIM Record: " -NoNewline -ForegroundColor White
$dkimStatus = Test-DkimRecordPresence -DomainName $domainToTest
if ($dkimStatus -like "PRESENT*") {
Write-Host "✅ $dkimStatus" -ForegroundColor Green
} elseif ($dkimStatus -eq "DNS_TIMEOUT") {
Write-Host "⏱️ DNS Timeout" -ForegroundColor Red
} else {
Write-Host "❌ Not Found" -ForegroundColor Red
}
Write-Host " DMARC Record: " -NoNewline -ForegroundColor White
$dmarcStatus = Test-DmarcRecordPresence -DomainName $domainToTest
switch ($dmarcStatus) {
"PRESENT_REJECT" { Write-Host "✅ Present (Policy: Reject)" -ForegroundColor Green }
"PRESENT_QUARANTINE" { Write-Host "⚠️ Present (Policy: Quarantine)" -ForegroundColor Yellow }
"PRESENT_NONE" { Write-Host "⚠️ Present (Policy: None)" -ForegroundColor Yellow }
"PRESENT_UNCLEAR" { Write-Host "⚠️ Present (Policy: Unclear)" -ForegroundColor Yellow }
"DNS_TIMEOUT" { Write-Host "⏱️ DNS Timeout" -ForegroundColor Red }
default { Write-Host "❌ Not Found" -ForegroundColor Red }
}
Write-Host ""
Write-Host "ℹ️ Note: DNS queries have a $Global:DnsTimeoutSeconds-second timeout limit." -ForegroundColor Gray
Write-Host ""
Read-Host "Press Enter to return to main menu"
}
function Show-EmailProviderInformation {
Clear-Host
Show-AsciiArtBanner
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor Blue
Write-Host "│ EMAIL PROVIDER PATTERNS │" -ForegroundColor Blue
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor Blue
Write-Host ""
Write-Host "🔵 GOOGLE WORKSPACE / GMAIL MX RECORDS:" -ForegroundColor Green
Write-Host " • aspmx.l.google.com" -ForegroundColor Gray
Write-Host " • alt1.aspmx.l.google.com through alt4.aspmx.l.google.com" -ForegroundColor Gray
Write-Host " • gmail-smtp-in.l.google.com" -ForegroundColor Gray
Write-Host " • googlemail.com" -ForegroundColor Gray
Write-Host ""
Write-Host "🔵 MICROSOFT 365 / OUTLOOK MX RECORDS:" -ForegroundColor Blue
Write-Host " • *.mail.protection.outlook.com" -ForegroundColor Gray
Write-Host " • *.outlook.com" -ForegroundColor Gray
Write-Host " • outlook.office365.com" -ForegroundColor Gray
Write-Host " • *.onmicrosoft.com" -ForegroundColor Gray
Write-Host " • mx1.hotmail.com through mx4.hotmail.com" -ForegroundColor Gray
Write-Host ""
Write-Host "🔵 OTHER PROVIDERS:" -ForegroundColor Magenta
Write-Host " All other email providers will be identified by their actual MX record hostnames." -ForegroundColor Gray
Write-Host " Common examples include: Yahoo, GoDaddy, Cloudflare, custom mail servers." -ForegroundColor Gray
Write-Host ""
Read-Host "Press Enter to return to main menu"
}
function Show-EmailSecurityStandardsGuide {
Clear-Host
Show-AsciiArtBanner
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor Magenta
Write-Host "│ EMAIL SECURITY STANDARDS GUIDE │" -ForegroundColor Magenta
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor Magenta
Write-Host ""
Write-Host "🛡️ SPF (SENDER POLICY FRAMEWORK):" -ForegroundColor Green
Write-Host " Purpose: Defines which mail servers are authorized to send email for a domain" -ForegroundColor Gray
Write-Host " Location: TXT record at domain root (e.g., example.com)" -ForegroundColor Gray
Write-Host " Format: Begins with 'v=spf1039;" -ForegroundColor Gray
Write-Host " Benefit: Prevents email spoofing and unauthorized sending" -ForegroundColor Gray
Write-Host ""
Write-Host "🛡️ DKIM (DOMAINKEYS IDENTIFIED MAIL):" -ForegroundColor Blue
Write-Host " Purpose: Adds cryptographic signature to verify email authenticity" -ForegroundColor Gray
Write-Host " Location: TXT record at selector._domainkey.domain.com" -ForegroundColor Gray
Write-Host " Format: Contains 'v=DKIM1039; and public key information" -ForegroundColor Gray
Write-Host " Common Selectors: default, selector1, selector2, google, k1" -ForegroundColor Gray
Write-Host " Benefit: Ensures email content integrity and sender verification" -ForegroundColor Gray
Write-Host ""
Write-Host "🛡️ DMARC (DOMAIN-BASED MESSAGE AUTHENTICATION):" -ForegroundColor Magenta
Write-Host " Purpose: Policy framework for handling SPF and DKIM authentication failures" -ForegroundColor Gray
Write-Host " Location: TXT record at _dmarc.domain.com" -ForegroundColor Gray
Write-Host " Format: Begins with 'v=DMARC1039;" -ForegroundColor Gray
Write-Host " Policies:" -ForegroundColor Gray
Write-Host " • p=none (monitoring only) - ⚠️ Weakest protection" -ForegroundColor Yellow
Write-Host " • p=quarantine (suspicious folder) - ⚠️ Moderate protection" -ForegroundColor Yellow
Write-Host " • p=reject (block delivery) - ✅ Strongest protection" -ForegroundColor Green
Write-Host " Benefit: Comprehensive email authentication policy enforcement" -ForegroundColor Gray
Write-Host ""
Write-Host "📊 RESULT COLOR CODING:" -ForegroundColor Cyan
Write-Host " ✅ Green = Security record present and optimally configured" -ForegroundColor Green
Write-Host " ⚠️ Yellow = Present but suboptimal (DMARC not set to reject)" -ForegroundColor Yellow
Write-Host " ❌ Red = Not found, DNS error, or timeout occurred" -ForegroundColor Red
Write-Host ""
Write-Host "⚙️ OPTIMIZATION FEATURES:" -ForegroundColor Cyan
Write-Host " • $Global:DnsTimeoutSeconds-second timeout per DNS query prevents hanging" -ForegroundColor Gray
Write-Host " • Domain caching reduces redundant queries for efficiency" -ForegroundColor Gray
Write-Host " • Concurrent processing for faster bulk analysis" -ForegroundColor Gray
Write-Host " • Prioritized selector checking for common DKIM patterns" -ForegroundColor Gray
Write-Host ""
Read-Host "Press Enter to return to main menu"
}
function Show-SystemConfigurationInfo {
Clear-Host
Show-AsciiArtBanner
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor DarkCyan
Write-Host "│ SYSTEM CONFIGURATION & REQUIREMENTS │" -ForegroundColor DarkCyan
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor DarkCyan
Write-Host ""
Write-Host "📁 FILE REQUIREMENTS:" -ForegroundColor Yellow
Write-Host " Input File: $Global:InputFileName" -ForegroundColor Green
Write-Host " Output File: $Global:OutputFileName" -ForegroundColor Green
Write-Host " Location: Same directory as this script" -ForegroundColor Gray
Write-Host ""
Write-Host "📋 REQUIRED CSV FORMAT:" -ForegroundColor Yellow
Write-Host " The input CSV must have a header row with a column named 'Email039;" -ForegroundColor Gray
Write-Host " Example format:" -ForegroundColor Gray
Write-Host " ┌─────────────────────────┐" -ForegroundColor DarkGray
Write-Host " │ Email │" -ForegroundColor DarkGray
Write-Host " ├─────────────────────────┤" -ForegroundColor DarkGray
Write-Host " │ user1@example.com │" -ForegroundColor DarkGray
Write-Host " │ user2@company.org │" -ForegroundColor DarkGray
Write-Host " │ admin@business.net │" -ForegroundColor DarkGray
Write-Host " └─────────────────────────┘" -ForegroundColor DarkGray
Write-Host ""
Write-Host "📊 OUTPUT CSV COLUMNS:" -ForegroundColor Yellow
Write-Host " • EmailAddress - Original email address from input" -ForegroundColor Gray
Write-Host " • EmailProvider - Detected email service provider" -ForegroundColor Gray
Write-Host " • SPF_Record - SPF record presence status" -ForegroundColor Gray
Write-Host " • DKIM_Record - DKIM record presence and selectors" -ForegroundColor Gray
Write-Host " • DMARC_Record - DMARC record presence and policy" -ForegroundColor Gray
Write-Host " • DMARC_Reject_Policy - Whether DMARC uses strongest reject policy" -ForegroundColor Gray
Write-Host ""
Write-Host "⚙️ CURRENT CONFIGURATION:" -ForegroundColor Yellow
Write-Host " • DNS Query Timeout: $Global:DnsTimeoutSeconds seconds" -ForegroundColor Gray
Write-Host " • Max Concurrent Jobs: $Global:MaxConcurrentJobs" -ForegroundColor Gray
Write-Host " • Domain Caching: Enabled for performance" -ForegroundColor Gray
Write-Host " • Input File Check: Automatic validation" -ForegroundColor Gray
Write-Host ""
Write-Host "💻 SYSTEM REQUIREMENTS:" -ForegroundColor Yellow
Write-Host " • PowerShell 5.1 or higher" -ForegroundColor Gray
Write-Host " • Network connectivity for DNS queries" -ForegroundColor Gray
Write-Host " • Read/Write permissions in script directory" -ForegroundColor Gray
Write-Host " • Windows DNS resolution services" -ForegroundColor Gray
Write-Host ""
$currentLocation = Get-Location
Write-Host "📍 CURRENT SCRIPT DIRECTORY:" -ForegroundColor Yellow
Write-Host " $currentLocation" -ForegroundColor Green
Write-Host ""
# Check if input file exists
$inputFilePath = Join-Path $currentLocation $Global:InputFileName
if (Test-Path $inputFilePath) {
Write-Host "✅ Input file found: $Global:InputFileName" -ForegroundColor Green
$fileStats = Get-Item $inputFilePath
Write-Host " File size: $([math]::Round($fileStats.Length / 1KB, 2)) KB" -ForegroundColor Gray
Write-Host " Last modified: $($fileStats.LastWriteTime)" -ForegroundColor Gray
} else {
Write-Host "❌ Input file not found: $Global:InputFileName" -ForegroundColor Red
Write-Host " Please create this file in the script directory before running analysis." -ForegroundColor Yellow
}
Write-Host ""
Read-Host "Press Enter to return to main menu"
}
function Start-QuickDomainTest {
Write-Host ""
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor Yellow
Write-Host "│ QUICK TEST MODE │" -ForegroundColor Yellow
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor Yellow
Write-Host ""
Write-Host "⚡ This mode processes only the first 5 email addresses for rapid testing." -ForegroundColor Cyan
Write-Host "💡 Perfect for validating the script functionality before large-scale analysis." -ForegroundColor Cyan
Write-Host ""
Start-BulkEmailSecurityAnalysis -MaxEmailsToProcess 5
}
function Start-BulkEmailSecurityAnalysis {
param(
[int]$MaxEmailsToProcess = 0
)
Write-Host ""
Write-Host "┌────────────────────────────────────────────────────────────────────────────┐" -ForegroundColor Green
Write-Host "│ BULK SECURITY ANALYSIS │" -ForegroundColor Green
Write-Host "└────────────────────────────────────────────────────────────────────────────┘" -ForegroundColor Green
Write-Host ""
$currentDirectory = Get-Location
$inputFilePath = Join-Path $currentDirectory $Global:InputFileName
$outputFilePath = Join-Path $currentDirectory $Global:OutputFileName
# Validate input file existence
if (-not (Test-Path $inputFilePath)) {
Write-Host "❌ ERROR: Input file not found!" -ForegroundColor Red
Write-Host " Expected location: $inputFilePath" -ForegroundColor Yellow
Write-Host " Please ensure '$Global:InputFileName039; exists in the script directory." -ForegroundColor Yellow
Write-Host ""
Read-Host "Press Enter to return to main menu"
return
}
try {
Write-Host "📖 Reading and validating CSV file..." -ForegroundColor Cyan
$emailDataFromCsv = Import-Csv -Path $inputFilePath -ErrorAction Stop
if (-not $emailDataFromCsv) {
Write-Host "❌ ERROR: CSV file is empty or has no data rows." -ForegroundColor Red
Write-Host " Ensure your CSV has a header row and at least one data row." -ForegroundColor Yellow
Write-Host ""
Read-Host "Press Enter to return to main menu"
return
}
# Validate CSV structure
$csvHeaders = $emailDataFromCsv[0].PSObject.Properties.Name
if ("Email" -notin $csvHeaders) {
Write-Host "❌ ERROR: Required 'Email039; column not found in CSV." -ForegroundColor Red
Write-Host " Available columns: $($csvHeaders -join ', 039;)" -ForegroundColor Yellow
Write-Host " Please ensure your CSV has a column named 'Email039;." -ForegroundColor Yellow
Write-Host ""
Read-Host "Press Enter to return to main menu"
return
}
Write-Host "✅ CSV validation successful!" -ForegroundColor Green
Write-Host " Total email addresses found: $($emailDataFromCsv.Count)" -ForegroundColor Gray
Write-Host ""
# Determine emails to process
$emailsToAnalyze = if ($MaxEmailsToProcess -gt 0 -and $MaxEmailsToProcess -lt $emailDataFromCsv.Count) {
$emailDataFromCsv | Select-Object -First $MaxEmailsToProcess
} else {
$emailDataFromCsv
}
$totalEmailCount = $emailsToAnalyze.Count
$processedEmailCount = 0
if ($MaxEmailsToProcess -gt 0) {
Write-Host "⚡ QUICK TEST MODE: Processing first $totalEmailCount email addresses..." -ForegroundColor Yellow
} else {
Write-Host "🔄 FULL ANALYSIS: Processing all $totalEmailCount email addresses..." -ForegroundColor Green
}
Write-Host "⏱️ Estimated time: $([math]::Ceiling($totalEmailCount * 3 / 60)) minutes (with DNS timeouts)" -ForegroundColor Gray
Write-Host "📁 Results will be saved to: $outputFilePath" -ForegroundColor Gray
Write-Host ""
# Initialize output CSV with clear, user-friendly headers
$csvHeaders = "Email_Address,Email_Provider,SPF_Status,SPF_Description,DKIM_Status,DKIM_Description,DMARC_Status,DMARC_Policy,DMARC_Strength,Security_Score,Overall_Security,Sales_Outreach_Email"
$csvHeaders | Out-File -FilePath $outputFilePath -Encoding UTF8 -Force
# Initialize summary statistics
$analysisResults = @()
foreach ($emailRow in $emailsToAnalyze) {
$processedEmailCount++
$emailAddress = $emailRow.Email
if ([string]::IsNullOrWhiteSpace($emailAddress)) {
Write-Host "[$processedEmailCount/$totalEmailCount] ⚠️ Skipping empty email address" -ForegroundColor Yellow
continue
}
# Extract domain
$domainName = Extract-DomainFromEmailAddress -EmailAddress $emailAddress
if (-not $domainName) {
Write-Host "[$processedEmailCount/$totalEmailCount] ❌ Invalid email format: $emailAddress" -ForegroundColor Red
$invalidResult = [PSCustomObject]@{
EmailAddress = $emailAddress
EmailProvider = "INVALID_EMAIL_FORMAT"
SPF_Record = "N/A"
DKIM_Record = "N/A"
DMARC_Record = "N/A"
DMARC_Reject_Policy = "N/A"
}
$analysisResults += $invalidResult
# Write to CSV
$csvLine = "`"$($invalidResult.EmailAddress)`",`"$($invalidResult.EmailProvider)`",`"$($invalidResult.SPF_Record)`",`"$($invalidResult.DKIM_Record)`",`"$($invalidResult.DMARC_Record)`",`"$($invalidResult.DMARC_Reject_Policy)`""
$csvLine | Out-File -FilePath $outputFilePath -Append -Encoding UTF8
continue
}
Write-Host "[$processedEmailCount/$totalEmailCount] 🔍 Analyzing: $emailAddress → $domainName" -ForegroundColor Gray
# Perform security analysis
$emailProvider = Get-EmailProviderFromMxRecords -DomainName $domainName
$spfStatus = Test-SpfRecordPresence -DomainName $domainName
$dkimStatus = Test-DkimRecordPresence -DomainName $domainName
$dmarcStatus = Test-DmarcRecordPresence -DomainName $domainName
# Convert technical status to user-friendly descriptions
# SPF Processing
$spfDescription = switch ($spfStatus) {
"PRESENT" { "✅ Configured"; $spfReadable = "Yes" }
"DNS_TIMEOUT" { "⏱️ DNS Timeout"; $spfReadable = "Unknown" }
"DNS_ERROR" { "❌ DNS Error"; $spfReadable = "Unknown" }
default { "❌ Not Found"; $spfReadable = "No" }
}
# DKIM Processing
$dkimDescription = switch -Wildcard ($dkimStatus) {
"PRESENT*" {
$selectorInfo = ($dkimStatus -replace "PRESENT \(", "" -replace "\)", "")
"✅ Configured ($selectorInfo)"
$dkimReadable = "Yes"
}
"DNS_TIMEOUT" { "⏱️ DNS Timeout"; $dkimReadable = "Unknown" }
"DNS_ERROR" { "❌ DNS Error"; $dkimReadable = "Unknown" }
default { "❌ Not Found"; $dkimReadable = "No" }
}
# DMARC Processing
$dmarcDescription = switch ($dmarcStatus) {
"PRESENT_REJECT" {
"✅ Configured - Reject Policy"
$dmarcReadable = "Yes"
$dmarcPolicy = "Reject (Strongest)"
$dmarcStrength = "Strong"
}
"PRESENT_QUARANTINE" {
"⚠️ Configured - Quarantine Policy"
$dmarcReadable = "Yes"
$dmarcPolicy = "Quarantine (Moderate)"
$dmarcStrength = "Moderate"
}
"PRESENT_NONE" {
"⚠️ Configured - Monitor Only"
$dmarcReadable = "Yes"
$dmarcPolicy = "None (Monitor Only)"
$dmarcStrength = "Weak"
}
"PRESENT_UNCLEAR" {
"⚠️ Configured - Policy Unclear"
$dmarcReadable = "Yes"
$dmarcPolicy = "Unclear"
$dmarcStrength = "Unknown"
}
"DNS_TIMEOUT" {
"⏱️ DNS Timeout"
$dmarcReadable = "Unknown"
$dmarcPolicy = "Unknown"
$dmarcStrength = "Unknown"
}
"DNS_ERROR" {
"❌ DNS Error"
$dmarcReadable = "Unknown"
$dmarcPolicy = "Unknown"
$dmarcStrength = "Unknown"
}
default {
"❌ Not Found"
$dmarcReadable = "No"
$dmarcPolicy = "Not Configured"
$dmarcStrength = "None"
}
}
# Calculate security score (out of 3)
$securityScore = 0
if ($spfReadable -eq "Yes") { $securityScore++ }
if ($dkimReadable -eq "Yes") { $securityScore++ }
if ($dmarcReadable -eq "Yes") { $securityScore++ }
# Overall security assessment
$overallSecurity = switch ($securityScore) {
3 { if ($dmarcStrength -eq "Strong") { "Excellent" } else { "Good" } }
2 { "Fair" }
1 { "Poor" }
0 { "Very Poor" }
}
# Generate personalized sales outreach email based on security analysis
$domainOnly = $domainName
$companyName = (Get-Culture).TextInfo.ToTitleCase($domainOnly.Split('.039;)[0])
$salesOutreachEmail = switch ($overallSecurity) {
"Excellent" {
"Hi! I noticed $companyName has excellent email security with all 3 key protections in place. That's impressive! While your setup is strong, I039;d love to show you how we help companies like yours maintain peak email deliverability and explore advanced optimization opportunities. Would you be open to a brief 15-minute call this week to discuss how we can ensure your emails always reach the inbox?"
}
"Good" {
"Hi! I ran a quick analysis on $companyName's email security and found you have solid foundations with SPF and DKIM configured. However, your DMARC policy could be strengthened to maximize email deliverability and protect against spoofing. This small adjustment could significantly improve your email performance. Would you have 15 minutes this week to discuss how we can optimize this for better inbox placement?"
}
"Fair" {
$missingItems = @()
if ($spfReadable -ne "Yes") { $missingItems += "SPF" }
if ($dkimReadable -ne "Yes") { $missingItems += "DKIM" }
if ($dmarcReadable -ne "Yes") { $missingItems += "DMARC" }
$missingText = $missingItems -join " and "
"Hi! I analyzed $companyName's email security and found some opportunities to improve your email deliverability. Currently missing $missingText protection, which means some of your emails might be landing in spam folders instead of inboxes. This directly impacts your sales and marketing results. Would you be interested in a quick 15-minute call to see how we can fix this and improve your email performance?"
}
"Poor" {
$configuredItems = @()
if ($spfReadable -eq "Yes") { $configuredItems += "SPF" }
if ($dkimReadable -eq "Yes") { $configuredItems += "DKIM" }
if ($dmarcReadable -eq "Yes") { $configuredItems += "DMARC" }
$configuredText = if ($configuredItems.Count -gt 0) { $configuredItems -join " and " } else { "basic" }
"Hi! I ran an email security check on $companyName and found significant deliverability risks. With only $configuredText protection in place, many of your emails are likely ending up in spam folders, hurting your sales and customer communication. This is costing you real business opportunities. Would you have 15 minutes this week for me to show you exactly what's happening and how we can quickly fix it?"
}
"Very Poor" {
"Hi! I discovered some urgent email deliverability issues with $companyName's domain. Your emails are currently at high risk of being blocked or marked as spam due to missing security protections. This means your sales emails, customer communications, and marketing campaigns aren039;t reaching their intended recipients. Would you be available for a brief 15-minute call this week? I can show you exactly what039;s happening and how we can resolve these issues quickly to get your emails back to the inbox."
}
default {
"Hi! I'd like to discuss some email deliverability opportunities I identified for $companyName. Would you be open to a brief 15-minute call this week to explore how we can improve your email performance?"
}
}
# Simplify email provider display
$simplifiedProvider = switch ($emailProvider) {
"Google" { "Google Workspace/Gmail" }
"Microsoft" { "Microsoft 365/Outlook" }
"DNS_TIMEOUT" { "DNS Timeout" }
"DNS_RESOLUTION_FAILED" { "DNS Error" }
"NO_MX_RECORDS" { "No Email Service" }
{ $_.Length -gt 50 } { "Custom Email Service" }
default { $emailProvider }
}
# Create result object with user-friendly data
$analysisResult = [PSCustomObject]@{
Email_Address = $emailAddress
Email_Provider = $simplifiedProvider
SPF_Status = $spfReadable
SPF_Description = $spfDescription
DKIM_Status = $dkimReadable
DKIM_Description = $dkimDescription
DMARC_Status = $dmarcReadable
DMARC_Policy = $dmarcPolicy
DMARC_Strength = $dmarcStrength
Security_Score = "$securityScore/3"
Overall_Security = $overallSecurity
Sales_Outreach_Email = $salesOutreachEmail
}
$analysisResults += $analysisResult
# Write to CSV immediately with proper escaping
$csvLine = "`"$($analysisResult.Email_Address)`",`"$($analysisResult.Email_Provider)`",`"$($analysisResult.SPF_Status)`",`"$($analysisResult.SPF_Description)`",`"$($analysisResult.DKIM_Status)`",`"$($analysisResult.DKIM_Description)`",`"$($analysisResult.DMARC_Status)`",`"$($analysisResult.DMARC_Policy)`",`"$($analysisResult.DMARC_Strength)`",`"$($analysisResult.Security_Score)`",`"$($analysisResult.Overall_Security)`",`"$($analysisResult.Sales_Outreach_Email)`""
$csvLine | Out-File -FilePath $outputFilePath -Append -Encoding UTF8
# Brief pause to prevent DNS server overload
Start-Sleep -Milliseconds 100
}
# Generate comprehensive summary
Write-Host ""
Write-Host "🎉 ANALYSIS COMPLETE!" -ForegroundColor Green
Write-Host "═══════════════════════════════════════════════════════════════════════════════" -ForegroundColor Green
Show-DetailedAnalysisSummary -Results $analysisResults -OutputPath $outputFilePath
}
catch {
Write-Host "❌ ERROR: Failed to process CSV file - $($_.Exception.Message)" -ForegroundColor Red
}
Write-Host ""
Read-Host "Press Enter to return to main menu"
}
function Show-DetailedAnalysisSummary {
param(
[array]$Results,
[string]$OutputPath
)
# Email provider statistics
$googleProviderCount = ($Results | Where-Object { $_.Email_Provider -like "*Google*" }).Count
$microsoftProviderCount = ($Results | Where-Object { $_.Email_Provider -like "*Microsoft*" }).Count
$dnsTimeoutCount = ($Results | Where-Object {
$_.Email_Provider -eq "DNS Timeout" -or
$_.SPF_Status -eq "Unknown" -or
$_.DKIM_Status -eq "Unknown" -or
$_.DMARC_Status -eq "Unknown"
}).Count
$otherProviderCount = $Results.Count - $googleProviderCount - $microsoftProviderCount - $dnsTimeoutCount
# Security record statistics
$spfPresentCount = ($Results | Where-Object { $_.SPF_Status -eq "Yes" }).Count
$dkimPresentCount = ($Results | Where-Object { $_.DKIM_Status -eq "Yes" }).Count
$dmarcPresentCount = ($Results | Where-Object { $_.DMARC_Status -eq "Yes" }).Count
$dmarcStrongCount = ($Results | Where-Object { $_.DMARC_Strength -eq "Strong" }).Count
# Overall security distribution
$excellentCount = ($Results | Where-Object { $_.Overall_Security -eq "Excellent" }).Count
$goodCount = ($Results | Where-Object { $_.Overall_Security -eq "Good" }).Count
$fairCount = ($Results | Where-Object { $_.Overall_Security -eq "Fair" }).Count
$poorCount = ($Results | Where-Object { $_.Overall_Security -eq "Poor" }).Count
$veryPoorCount = ($Results | Where-Object { $_.Overall_Security -eq "Very Poor" }).Count
Write-Host ""
Write-Host "📊 EMAIL PROVIDER DISTRIBUTION:" -ForegroundColor White
Write-Host " Total emails processed: $($Results.Count)" -ForegroundColor Gray
Write-Host " 🟢 Google Workspace/Gmail: $googleProviderCount ($(($googleProviderCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor Green
Write-Host " 🔵 Microsoft 365/Outlook: $microsoftProviderCount ($(($microsoftProviderCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor Blue
Write-Host " 🟣 Other providers: $otherProviderCount ($(($otherProviderCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor Magenta
if ($dnsTimeoutCount -gt 0) {
Write-Host " 🔴 DNS Timeouts: $dnsTimeoutCount ($(($dnsTimeoutCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor Red
}
Write-Host ""
Write-Host "🛡️ EMAIL SECURITY COMPLIANCE:" -ForegroundColor White
Write-Host " SPF Records Present: $spfPresentCount/$($Results.Count) ($(($spfPresentCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor $(if($spfPresentCount -eq $Results.Count){"Green"}else{"Yellow"})
Write-Host " DKIM Records Present: $dkimPresentCount/$($Results.Count) ($(($dkimPresentCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor $(if($dkimPresentCount -eq $Results.Count){"Green"}else{"Yellow"})
Write-Host " DMARC Records Present: $dmarcPresentCount/$($Results.Count) ($(($dmarcPresentCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor $(if($dmarcPresentCount -eq $Results.Count){"Green"}else{"Yellow"})
Write-Host " DMARC Reject Policy: $dmarcRejectCount/$($Results.Count) ($(($dmarcRejectCount/$Results.Count*100).ToString('F1039;))%)" -ForegroundColor $(if($dmarcRejectCount -eq $Results.Count){"Green"}else{"Red"})
Write-Host ""
# Security score calculation
$maxSecurityScore = $Results.Count * 3 # SPF + DKIM + DMARC
$actualSecurityScore = $spfPresentCount + $dkimPresentCount + $dmarcPresentCount
$securityScorePercentage = ($actualSecurityScore / $maxSecurityScore * 100).ToString('F1039;)
Write-Host "📈 OVERALL SECURITY SCORE:" -ForegroundColor White
Write-Host " $actualSecurityScore/$maxSecurityScore security records present ($securityScorePercentage%)" -ForegroundColor $(
if ([double]$securityScorePercentage -ge 90) { "Green" }
elseif ([double]$securityScorePercentage -ge 70) { "Yellow" }
else { "Red" }
)
Write-Host ""
Write-Host "💾 Results saved to: $OutputPath" -ForegroundColor Cyan
# Verify output file
if (Test-Path $OutputPath) {
$outputFileInfo = Get-Item $OutputPath
Write-Host " File size: $([math]::Round($outputFileInfo.Length / 1KB, 2)) KB" -ForegroundColor Gray
Write-Host " Created: $($outputFileInfo.CreationTime)" -ForegroundColor Gray
}
}
# ================================================================================
# MAIN SCRIPT EXECUTION LOOP
# ================================================================================
do {
Show-AsciiArtBanner
Show-MainNavigationMenu
$userMenuChoice = Read-Host "Select an option [1-7]"
switch ($userMenuChoice) {
"1" {
Start-BulkEmailSecurityAnalysis
}
"2" {
Start-QuickDomainTest
}
"3" {
Test-IndividualDomainSecurity
}
"4" {
Show-EmailProviderInformation
}
"5" {
Show-EmailSecurityStandardsGuide
}
"6" {
Show-SystemConfigurationInfo
}
"7" {
Write-Host ""
Write-Host "👋 Thank you for using Bulk Email Security Auditor!" -ForegroundColor Green
Write-Host " Developed by Aaron Kinder" -ForegroundColor Cyan
Write-Host ""
exit
}
default {
Write-Host ""
Write-Host "❌ Invalid selection. Please choose options 1-7." -ForegroundColor Red
Start-Sleep -Seconds 2
}
}
} while ($true)