Dargslan.WinPatchTuesday.psm1

<#
.SYNOPSIS
    Windows Patch Tuesday analysis toolkit — installed KBs, missing critical patches, patch age analysis, and update compliance scoring
.DESCRIPTION
    2026 Edition — Dargslan Windows Admin Toolkit.
    https://dargslan.com | https://dargslan.com/cheat-sheets
.LINK
    https://dargslan.com
#>


function Get-PatchTuesdayAudit {
    <#
    .SYNOPSIS
        Analyze patch compliance and missing critical updates
    .DESCRIPTION
        Part of Dargslan.WinPatchTuesday (2026 Edition) — https://dargslan.com
    #>

    [CmdletBinding()] param([switch]$Json)
    $report = [ordered]@{
        InstalledHotfixes = Get-HotFix -ErrorAction SilentlyContinue | Sort-Object InstalledOn -Descending | Select-Object -First 30 HotFixID, Description, InstalledOn, InstalledBy
        LastPatchDate = (Get-HotFix -ErrorAction SilentlyContinue | Sort-Object InstalledOn -Descending | Select-Object -First 1).InstalledOn
        PendingUpdates = (New-Object -ComObject Microsoft.Update.Session -ErrorAction SilentlyContinue).CreateUpdateSearcher().Search("IsInstalled=0").Updates | Select-Object -First 15 Title, @{N="KB";E={$_.KBArticleIDs -join ","}}, @{N="Severity";E={$_.MsrcSeverity}}, IsDownloaded
        OSBuild = [System.Environment]::OSVersion.Version
        WindowsVersion = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -ErrorAction SilentlyContinue) | Select-Object ProductName, DisplayVersion, CurrentBuild, UBR
        Summary = [PSCustomObject]@{ InstalledPatches = 0; PendingUpdates = 0; DaysSinceLastPatch = 0; LastPatch = "" }
    }
    $report.Summary.InstalledPatches = ($report.InstalledHotfixes | Measure-Object).Count
    $report.Summary.PendingUpdates = ($report.PendingUpdates | Measure-Object).Count
    if ($report.LastPatchDate) {
        $report.Summary.DaysSinceLastPatch = [math]::Round(((Get-Date) - $report.LastPatchDate).TotalDays, 0)
        $report.Summary.LastPatch = $report.LastPatchDate.ToString("yyyy-MM-dd")
    }
    $score = 100
    if ($report.Summary.DaysSinceLastPatch -gt 30) { $score -= 20 }
    if ($report.Summary.DaysSinceLastPatch -gt 60) { $score -= 30 }
    if ($report.Summary.PendingUpdates -gt 5) { $score -= 20 }
    $report.ComplianceScore = [PSCustomObject]@{ Score=[math]::Max(0,$score); Grade=$(if($score -ge 80){"A"}elseif($score -ge 60){"B"}else{"C"}) }
    if ($Json) { return $report | ConvertTo-Json -Depth 3 }
    Write-Host "`n [Patch Tuesday Analysis - 2026]" -ForegroundColor Cyan
    $report.Summary | Format-List
    $report.WindowsVersion | Format-List ProductName, DisplayVersion, CurrentBuild, UBR
    Write-Host " Compliance: $($report.ComplianceScore.Score)/100 ($($report.ComplianceScore.Grade))" -ForegroundColor $(if($score -ge 80){"Green"}elseif($score -ge 60){"Yellow"}else{"Red"})
    if ($report.InstalledHotfixes) { $report.InstalledHotfixes | Select-Object -First 10 | Format-Table -AutoSize }
    if ($report.PendingUpdates) { Write-Host " Pending Updates:" -ForegroundColor Yellow; $report.PendingUpdates | Format-Table Title, KB, Severity -AutoSize }
    return $report
}

Export-ModuleMember -Function *