In partnership with

THE PROBLEM

SSL certificates expire silently. No warning, no alert — just a red "Not Secure" screen in your users' browsers and a frantic call to IT. Worse, expired certs on internal servers can break authentication, API calls, and service-to-service communication without any obvious error message. This week we build a script that checks every certificate in your environment and emails you a weekly report showing exactly how many days each one has left.

THE SCRIPT

Save the script below to:

C:\Scripts\SSLCertMonitor.ps1

PowerShell

# SSL Certificate Expiry Monitor
# Automate & Operate — automateandoperate.com

# Settings — update these
$from = "[email protected]"
$to = "[email protected]"
$smtpServer = "smtp.email.com"
$smtpPort = 587
$username = "[email protected]"
$password = ConvertTo-SecureString "yourpassword" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($username, $password)
$logFile = "C:\Logs\SSLCertMonitor.log"

# Days threshold — alert if cert expires within this many days
$warningThresholdDays = 30
$criticalThresholdDays = 14

# List your domains and internal servers to check
$targets = @(
    @{ Host = "yourwebsite.com";     Port = 443 },
    @{ Host = "internalserver01";    Port = 443 },
    @{ Host = "internalserver02";    Port = 8443 },
    @{ Host = "mail.yourdomain.com"; Port = 443 }
)

# Create log folder if missing
if (-not (Test-Path "C:\Logs")) {
    New-Item -ItemType Directory -Path "C:\Logs"
}

$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
$report = @()
$warningCerts = @()
$criticalCerts = @()

foreach ($target in $targets) {
    try {
        $tcpClient = New-Object System.Net.Sockets.TcpClient($target.Host, $target.Port)
        $sslStream = New-Object System.Net.Security.SslStream($tcpClient.GetStream(), $false, {
            param($sender, $cert, $chain, $errors) return $true
        })
        $sslStream.AuthenticateAsClient($target.Host)
        $cert = $sslStream.RemoteCertificate
        $cert2 = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($cert)

        $expiryDate = $cert2.NotAfter
        $daysRemaining = (New-TimeSpan -Start (Get-Date) -End $expiryDate).Days

        $status = if ($daysRemaining -le $criticalThresholdDays) {
            "CRITICAL"
        } elseif ($daysRemaining -le $warningThresholdDays) {
            "WARNING"
        } else {
            "OK"
        }

        $report += [PSCustomObject]@{
            Host          = $target.Host
            Port          = $target.Port
            ExpiryDate    = $expiryDate.ToString("yyyy-MM-dd")
            DaysRemaining = $daysRemaining
            Status        = $status
        }

        if ($status -eq "CRITICAL") { $criticalCerts += $target.Host }
        if ($status -eq "WARNING")  { $warningCerts  += $target.Host }

        Add-Content -Path $logFile -Value "$timestamp$($target.Host):$($target.Port) — Expires: $expiryDate$daysRemaining days — $status"

        $sslStream.Close()
        $tcpClient.Close()

    } catch {
        $report += [PSCustomObject]@{
            Host          = $target.Host
            Port          = $target.Port
            ExpiryDate    = "UNREACHABLE"
            DaysRemaining = "N/A"
            Status        = "ERROR"
        }
        Add-Content -Path $logFile -Value "$timestamp$($target.Host):$($target.Port) — ERROR: $_"
    }
}

# Build email body
$emailBody = "SSL Certificate Expiry Report — $timestamp`n"
$emailBody += "Warning threshold: $warningThresholdDays days`n"
$emailBody += "Critical threshold: $criticalThresholdDays days`n`n"
$emailBody += "CERTIFICATE SUMMARY:`n"
$emailBody += "=" * 60 + "`n`n"

foreach ($entry in $report) {
    $emailBody += "Host:           $($entry.Host):$($entry.Port)`n"
    $emailBody += "Expiry Date:    $($entry.ExpiryDate)`n"
    $emailBody += "Days Remaining: $($entry.DaysRemaining)`n"
    $emailBody += "Status:         $($entry.Status)`n"
    $emailBody += "-" * 40 + "`n"
}

if ($criticalCerts.Count -gt 0) {
    $emailBody += "`nCRITICAL — Expires in under $criticalThresholdDays days:`n"
    $criticalCerts | ForEach-Object { $emailBody += "  !! $_`n" }
}

if ($warningCerts.Count -gt 0) {
    $emailBody += "`nWARNING — Expires in under $warningThresholdDays days:`n"
    $warningCerts | ForEach-Object { $emailBody += "  >> $_`n" }
}

$emailBody += "`Automate & Operate — automateandoperate.com"

# Set subject based on severity
$subject = if ($criticalCerts.Count -gt 0) {
    "CRITICAL: $($criticalCerts.Count) SSL cert(s) expiring in under $criticalThresholdDays days"
} elseif ($warningCerts.Count -gt 0) {
    "WARNING: $($warningCerts.Count) SSL cert(s) expiring in under $warningThresholdDays days"
} else {
    "SSL Cert Report — All certificates OK"
}

Send-MailMessage `
    -From $from -To $to `
    -Subject $subject `
    -Body $emailBody `
    -SmtpServer $smtpServer -Port $smtpPort `
    -UseSsl -Credential $credential

Update these lines:

  • $from / $to / $username / $password — your Email details

  • $targets — replace with your actual domains and internal servers

  • $warningThresholdDays — days before expiry to send a warning (default 30)

  • $criticalThresholdDays — days before expiry to send a critical alert (default 14)

SETTING UP TASK SCHEDULER

  1. Press Windows key → type Task Scheduler → open it

  2. Click "Create Basic Task" → name it SSL Cert Monitor

  3. Trigger: Weekly → Monday → 7:00am

  4. Action: Start a program

  5. Program: powershell.exe

  6. Arguments:

-ExecutionPolicy Bypass -File "C:\Scripts\SSLCertMonitor.ps1"
  1. Click Next → Finish

Every Monday morning you'll have a full SSL report in your inbox before the week starts.

TEST IT

Open PowerShell as administrator and run:

PowerShell

powershell.exe -ExecutionPolicy Bypass -File "C:\Scripts\SSLCertMonitor.ps1"

To force a warning alert for testing, temporarily set $warningThresholdDays = 365 — this will flag any cert expiring within a year and guarantee you get an email.

Check C:\Logs\SSLCertMonitor.log to confirm it's logging each certificate correctly.

WHY THIS MATTERS

A single expired certificate can take down your website, break your email, invalidate your VPN, or silently corrupt API integrations between services. Most teams only find out when something stops working. This script gives you a 30-day runway to renew before anything breaks — and a 14-day critical alert if you missed the first warning.

THIS WEEK'S ACTION

Add your top 5 external domains and your most critical internal servers to the $targets list and run this today. You might find certificates expiring sooner than you think.

Reply to this email if you hit any issues — I read every reply.

Automate & Operate — automateandoperate.com

Write docs 4x faster. Without hating every second.

Nobody became a developer to write documentation. But the docs still need to get written — PRDs, README updates, architecture decisions, onboarding guides.

Wispr Flow lets you talk through it instead. Speak naturally about what the code does, how it works, and why you built it that way. Flow formats everything into clean, professional text you can paste into Notion, Confluence, or GitHub.

Used by engineering teams at OpenAI, Vercel, and Clay. 89% of messages sent with zero edits. Works system-wide on Mac, Windows, and iPhone.

Go from AI overwhelmed to AI savvy professional

AI will eliminate 300 million jobs in the next 5 years.

Yours doesn't have to be one of them.

Here's how to future-proof your career:

  • Join the Superhuman AI newsletter - read by 1M+ professionals

  • Learn AI skills in 3 mins a day

  • Become the AI expert on your team

Keep Reading