Vulnerability/Find-EOLSoftware.ps1

function Find-EOLSoftware {
    <#
    .SYNOPSIS
        Detects end-of-life (EOL) and unsupported software installations
    .DESCRIPTION
        Scans installed software and identifies applications that have reached
        end-of-life, are no longer supported, or are critically outdated.
        Provides security risk assessment and upgrade recommendations.
    .PARAMETER IncludeExpiringSoon
        Include software expiring within specified months (default: 6)
    .PARAMETER ExpiringMonths
        Number of months to check for expiring support (default: 6)
    .PARAMETER OutputPath
        Path to save EOL software report
    .PARAMETER Format
        Report format: HTML, JSON, CSV, or All
    .EXAMPLE
        Find-EOLSoftware
        Find-EOLSoftware -IncludeExpiringSoon -ExpiringMonths 12 -OutputPath "C:\Reports"
    .OUTPUTS
        PSCustomObject with EOL software findings
    #>

    
    [CmdletBinding()]
    param(
        [Parameter()]
        [switch]$IncludeExpiringSoon,
        
        [Parameter()]
        [int]$ExpiringMonths = 6,
        
        [Parameter()]
        [string]$OutputPath,
        
        [Parameter()]
        [ValidateSet('HTML', 'JSON', 'CSV', 'All')]
        [string]$Format = 'HTML'
    )
    
    begin {
        Write-Host "=== END-OF-LIFE SOFTWARE DETECTION ===" -ForegroundColor Cyan
        Write-Host "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Yellow
        Write-Host "Include Expiring Soon: $(if($IncludeExpiringSoon){'Yes'}else{'No'})" -ForegroundColor Yellow
        if ($IncludeExpiringSoon) {
            Write-Host "Expiring Within: $ExpiringMonths months" -ForegroundColor Yellow
        }
        
        $findings = [PSCustomObject]@{
            ScanDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            ComputerName = $env:COMPUTERNAME
            TotalSoftware = 0
            EOLSoftware = @()
            ExpiringSoon = @()
            Summary = @{
                TotalEOL = 0
                CriticalRisk = 0
                HighRisk = 0
                MediumRisk = 0
                TotalExpiring = 0
            }
            Recommendations = @()
        }
        
        # Known EOL Software Database
        $eolDatabase = @{
            'Windows 7' = @{
                EOLDate = [DateTime]'2020-01-14'
                Severity = 'Critical'
                Replacement = 'Windows 10/11'
                Notes = 'No security updates since January 2020'
            }
            'Windows 8' = @{
                EOLDate = [DateTime]'2016-01-12'
                Severity = 'Critical'
                Replacement = 'Windows 10/11'
                Notes = 'Extended support ended'
            }
            'Windows Server 2008' = @{
                EOLDate = [DateTime]'2020-01-14'
                Severity = 'Critical'
                Replacement = 'Windows Server 2019/2022'
                Notes = 'Critical security risk - no patches'
            }
            'Windows Server 2012' = @{
                EOLDate = [DateTime]'2023-10-10'
                Severity = 'Critical'
                Replacement = 'Windows Server 2019/2022'
                Notes = 'Extended support ended October 2023'
            }
            'Office 2010' = @{
                EOLDate = [DateTime]'2020-10-13'
                Severity = 'High'
                Replacement = 'Microsoft 365 / Office 2021'
                Notes = 'No security updates available'
            }
            'Office 2013' = @{
                EOLDate = [DateTime]'2023-04-11'
                Severity = 'High'
                Replacement = 'Microsoft 365 / Office 2021'
                Notes = 'Extended support ended April 2023'
            }
            'Office 2016' = @{
                EOLDate = [DateTime]'2025-10-14'
                Severity = 'Medium'
                Replacement = 'Microsoft 365 / Office 2021'
                Notes = 'Approaching end of support'
            }
            'SQL Server 2008' = @{
                EOLDate = [DateTime]'2019-07-09'
                Severity = 'Critical'
                Replacement = 'SQL Server 2019/2022'
                Notes = 'Critical database security risk'
            }
            'SQL Server 2012' = @{
                EOLDate = [DateTime]'2022-07-12'
                Severity = 'Critical'
                Replacement = 'SQL Server 2019/2022'
                Notes = 'Extended support ended'
            }
            'SQL Server 2014' = @{
                EOLDate = [DateTime]'2024-07-09'
                Severity = 'High'
                Replacement = 'SQL Server 2019/2022'
                Notes = 'Extended support ending soon'
            }
            'Internet Explorer' = @{
                EOLDate = [DateTime]'2022-06-15'
                Severity = 'Critical'
                Replacement = 'Microsoft Edge'
                Notes = 'Disabled by Microsoft - security risk'
            }
            'Adobe Flash Player' = @{
                EOLDate = [DateTime]'2020-12-31'
                Severity = 'Critical'
                Replacement = 'Modern web standards (HTML5)'
                Notes = 'Blocked by all major browsers'
            }
            'Java SE 7' = @{
                EOLDate = [DateTime]'2015-04-14'
                Severity = 'Critical'
                Replacement = 'Java SE 17 LTS or 21 LTS'
                Notes = 'Multiple critical vulnerabilities'
            }
            'Java SE 8' = @{
                EOLDate = [DateTime]'2030-12-31'
                Severity = 'Low'
                Replacement = 'Java SE 17 LTS or 21 LTS'
                Notes = 'Public updates ended (commercial available)'
            }
            'Python 2' = @{
                EOLDate = [DateTime]'2020-01-01'
                Severity = 'High'
                Replacement = 'Python 3.9+'
                Notes = 'No bug fixes or security updates'
            }
            'PHP 7.2' = @{
                EOLDate = [DateTime]'2020-11-30'
                Severity = 'High'
                Replacement = 'PHP 8.1+'
                Notes = 'Security support ended'
            }
            'PHP 7.3' = @{
                EOLDate = [DateTime]'2021-12-06'
                Severity = 'High'
                Replacement = 'PHP 8.1+'
                Notes = 'Security support ended'
            }
            'PHP 7.4' = @{
                EOLDate = [DateTime]'2022-11-28'
                Severity = 'High'
                Replacement = 'PHP 8.1+'
                Notes = 'Security support ended'
            }
            'Node.js 10' = @{
                EOLDate = [DateTime]'2021-04-30'
                Severity = 'High'
                Replacement = 'Node.js 18 LTS or 20 LTS'
                Notes = 'No security updates'
            }
            'Node.js 12' = @{
                EOLDate = [DateTime]'2022-04-30'
                Severity = 'High'
                Replacement = 'Node.js 18 LTS or 20 LTS'
                Notes = 'No security updates'
            }
            '.NET Framework 4.5' = @{
                EOLDate = [DateTime]'2016-01-12'
                Severity = 'High'
                Replacement = '.NET 6/7/8'
                Notes = 'Upgrade to supported version'
            }
        }
    }
    
    process {
        try {
            # 1. SCAN INSTALLED SOFTWARE
            Write-Host "`n[1/3] Scanning installed software..." -ForegroundColor Cyan
            
            $registryPaths = @(
                'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*',
                'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*'
            )
            
            $installedSoftware = @()
            foreach ($path in $registryPaths) {
                $items = Get-ItemProperty $path -ErrorAction SilentlyContinue
                if ($items) {
                    foreach ($item in $items) {
                        if ($null -ne $item.PSObject.Properties['DisplayName'] -and 
                            $null -ne $item.DisplayName -and 
                            $item.DisplayName -ne '') {
                            
                            $displayVersion = if ($null -ne $item.PSObject.Properties['DisplayVersion']) { 
                                $item.DisplayVersion 
                            } else { 
                                'Unknown' 
                            }
                            
                            $publisher = if ($null -ne $item.PSObject.Properties['Publisher']) { 
                                $item.Publisher 
                            } else { 
                                'Unknown' 
                            }
                            
                            $installedSoftware += [PSCustomObject]@{
                                DisplayName = $item.DisplayName
                                DisplayVersion = $displayVersion
                                Publisher = $publisher
                            }
                        }
                    }
                }
            }
            
            $installedSoftware = @($installedSoftware | Sort-Object DisplayName -Unique)
            $findings.TotalSoftware = $installedSoftware.Count
            
            Write-Host " Found $($installedSoftware.Count) installed applications" -ForegroundColor Gray
            
            # 2. CHECK AGAINST EOL DATABASE
            Write-Host "`n[2/3] Checking against EOL database..." -ForegroundColor Cyan
            
            $currentDate = Get-Date
            $expiringThreshold = $currentDate.AddMonths($ExpiringMonths)
            
            foreach ($software in $installedSoftware) {
                foreach ($eolName in $eolDatabase.Keys) {
                    if ($software.DisplayName -like "*$eolName*") {
                        $eolInfo = $eolDatabase[$eolName]
                        
                        # Check if EOL or expiring soon
                        $isEOL = $currentDate -gt $eolInfo.EOLDate
                        $isExpiringSoon = ($eolInfo.EOLDate -gt $currentDate) -and 
                                         ($eolInfo.EOLDate -le $expiringThreshold)
                        
                        if ($isEOL) {
                            $daysSinceEOL = [Math]::Round(($currentDate - $eolInfo.EOLDate).TotalDays)
                            
                            $eolSoftware = [PSCustomObject]@{
                                Name = $software.DisplayName
                                Version = $software.DisplayVersion
                                Publisher = $software.Publisher
                                EOLDate = $eolInfo.EOLDate.ToString('yyyy-MM-dd')
                                DaysSinceEOL = $daysSinceEOL
                                Severity = $eolInfo.Severity
                                Replacement = $eolInfo.Replacement
                                Notes = $eolInfo.Notes
                                Status = 'End-of-Life'
                            }
                            
                            $findings.EOLSoftware += $eolSoftware
                            $findings.Summary.TotalEOL++
                            
                            # Update risk counters
                            switch ($eolInfo.Severity) {
                                'Critical' { $findings.Summary.CriticalRisk++ }
                                'High' { $findings.Summary.HighRisk++ }
                                'Medium' { $findings.Summary.MediumRisk++ }
                            }
                            
                            $color = switch ($eolInfo.Severity) {
                                'Critical' { 'Red' }
                                'High' { 'Yellow' }
                                default { 'Gray' }
                            }
                            
                            Write-Host " [!] EOL: $($software.DisplayName) - $($eolInfo.Severity) risk ($daysSinceEOL days past EOL)" -ForegroundColor $color
                        }
                        elseif ($isExpiringSoon -and $IncludeExpiringSoon) {
                            $daysUntilEOL = [Math]::Round(($eolInfo.EOLDate - $currentDate).TotalDays)
                            
                            $expiringSoftware = [PSCustomObject]@{
                                Name = $software.DisplayName
                                Version = $software.DisplayVersion
                                Publisher = $software.Publisher
                                EOLDate = $eolInfo.EOLDate.ToString('yyyy-MM-dd')
                                DaysUntilEOL = $daysUntilEOL
                                Severity = $eolInfo.Severity
                                Replacement = $eolInfo.Replacement
                                Notes = $eolInfo.Notes
                                Status = 'Expiring Soon'
                            }
                            
                            $findings.ExpiringSoon += $expiringSoftware
                            $findings.Summary.TotalExpiring++
                            
                            Write-Host " [*] Expiring: $($software.DisplayName) - EOL in $daysUntilEOL days" -ForegroundColor Yellow
                        }
                    }
                }
            }
            
            Write-Host " Found $($findings.Summary.TotalEOL) EOL software" -ForegroundColor $(
                if ($findings.Summary.TotalEOL -gt 0) { 'Red' } else { 'Green' }
            )
            
            if ($IncludeExpiringSoon) {
                Write-Host " Found $($findings.Summary.TotalExpiring) expiring soon" -ForegroundColor $(
                    if ($findings.Summary.TotalExpiring -gt 0) { 'Yellow' } else { 'Green' }
                )
            }
            
            # 3. GENERATE RECOMMENDATIONS
            Write-Host "`n[3/3] Generating recommendations..." -ForegroundColor Cyan
            
            if ($findings.Summary.CriticalRisk -gt 0) {
                $findings.Recommendations += "CRITICAL: Remove or upgrade $($findings.Summary.CriticalRisk) critically outdated software immediately"
            }
            
            if ($findings.Summary.HighRisk -gt 0) {
                $findings.Recommendations += "HIGH: Plan migration for $($findings.Summary.HighRisk) high-risk EOL software within 30 days"
            }
            
            if ($findings.Summary.MediumRisk -gt 0) {
                $findings.Recommendations += "MEDIUM: Schedule upgrades for $($findings.Summary.MediumRisk) medium-risk software"
            }
            
            if ($findings.Summary.TotalExpiring -gt 0) {
                $findings.Recommendations += "Plan upgrades for $($findings.Summary.TotalExpiring) software approaching EOL"
            }
            
            if ($findings.Summary.TotalEOL -eq 0 -and $findings.Summary.TotalExpiring -eq 0) {
                $findings.Recommendations += "No EOL or expiring software detected - maintain current update schedule"
            }
            
            $findings.Recommendations += "Implement software lifecycle management policy"
            $findings.Recommendations += "Subscribe to vendor EOL announcements"
            $findings.Recommendations += "Conduct quarterly EOL software audits"
            $findings.Recommendations += "Block installation of EOL software via Group Policy"
            
            # 4. EXPORT REPORTS
            if ($OutputPath) {
                Write-Host "`n[*] Exporting EOL software reports..." -ForegroundColor Cyan
                
                if (-not (Test-Path $OutputPath)) {
                    New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
                }
                
                $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
                $reportName = "EOLSoftware_$timestamp"
                
                # Export JSON
                if ($Format -in @('JSON', 'All')) {
                    $jsonPath = Join-Path $OutputPath "$reportName.json"
                    $findings | ConvertTo-Json -Depth 10 | Out-File $jsonPath -Encoding UTF8
                    Write-Host " JSON report saved: $jsonPath" -ForegroundColor Green
                }
                
                # Export CSV
                if ($Format -in @('CSV', 'All')) {
                    $csvPath = Join-Path $OutputPath "$reportName.csv"
                    $allFindings = $findings.EOLSoftware + $findings.ExpiringSoon
                    $allFindings | Export-Csv $csvPath -NoTypeInformation
                    Write-Host " CSV report saved: $csvPath" -ForegroundColor Green
                }
                
                # Export HTML
                if ($Format -in @('HTML', 'All')) {
                    $htmlPath = Join-Path $OutputPath "$reportName.html"
                    $html = Generate-EOLSoftwareHTML -Findings $findings
                    $html | Out-File $htmlPath -Encoding UTF8
                    Write-Host " HTML report saved: $htmlPath" -ForegroundColor Green
                }
            }
            
        }
        catch {
            Write-Error "Error during EOL software detection: $_"
            throw
        }
    }
    
    end {
        Write-Host "`n=== EOL SOFTWARE DETECTION COMPLETE ===" -ForegroundColor $(
            if ($findings.Summary.CriticalRisk -gt 0) { 'Red' }
            elseif ($findings.Summary.HighRisk -gt 0) { 'Yellow' }
            else { 'Green' }
        )
        
        Write-Host "`nSummary:" -ForegroundColor Cyan
        Write-Host " Total Software Scanned: $($findings.TotalSoftware)" -ForegroundColor White
        Write-Host " EOL Software: $($findings.Summary.TotalEOL)" -ForegroundColor $(
            if ($findings.Summary.TotalEOL -gt 0) { 'Red' } else { 'Green' }
        )
        Write-Host " Critical Risk: $($findings.Summary.CriticalRisk)" -ForegroundColor $(
            if ($findings.Summary.CriticalRisk -gt 0) { 'Red' } else { 'Gray' }
        )
        Write-Host " High Risk: $($findings.Summary.HighRisk)" -ForegroundColor $(
            if ($findings.Summary.HighRisk -gt 0) { 'Yellow' } else { 'Gray' }
        )
        Write-Host " Medium Risk: $($findings.Summary.MediumRisk)" -ForegroundColor Gray
        
        if ($IncludeExpiringSoon) {
            Write-Host " Expiring Soon: $($findings.Summary.TotalExpiring)" -ForegroundColor $(
                if ($findings.Summary.TotalExpiring -gt 0) { 'Yellow' } else { 'Gray' }
            )
        }
        
        if ($findings.EOLSoftware.Count -gt 0) {
            Write-Host "`nEOL Software Detected:" -ForegroundColor Cyan
            $findings.EOLSoftware | 
                Sort-Object { 
                    switch ($_.Severity) {
                        'Critical' { 0 }
                        'High' { 1 }
                        'Medium' { 2 }
                        default { 3 }
                    }
                } |
                Select-Object -First 10 |
                ForEach-Object {
                    $color = switch ($_.Severity) {
                        'Critical' { 'Red' }
                        'High' { 'Yellow' }
                        default { 'Gray' }
                    }
                    Write-Host " [$($_.Severity)] $($_.Name) - Replace with: $($_.Replacement)" -ForegroundColor $color
                }
        }
        
        if ($findings.Recommendations.Count -gt 0) {
            Write-Host "`nRecommendations:" -ForegroundColor Cyan
            $findings.Recommendations | ForEach-Object {
                Write-Host " ! $_" -ForegroundColor Yellow
            }
        }
        
        return $findings
    }
}

# Helper function to generate HTML report
function Generate-EOLSoftwareHTML {
    param($Findings)
    
    $riskColor = if($Findings.Summary.CriticalRisk -gt 0){'critical'}
                 elseif($Findings.Summary.HighRisk -gt 0){'high'}
                 else{'safe'}
    
    $html = @"
<!DOCTYPE html>
<html>
<head>
    <title>EOL Software Report - $($Findings.ComputerName)</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
        h1 { color: #2c3e50; border-bottom: 3px solid #e74c3c; padding-bottom: 10px; }
        h2 { color: #34495e; margin-top: 30px; }
        .summary { background: #ecf0f1; padding: 20px; border-radius: 5px; margin: 20px 0; }
        .metric { display: inline-block; margin: 10px 20px 10px 0; }
        .metric-label { font-weight: bold; color: #7f8c8d; }
        .metric-value { font-size: 24px; font-weight: bold; }
        .critical { color: #e74c3c; }
        .high { color: #e67e22; }
        .medium { color: #f39c12; }
        .low { color: #95a5a6; }
        .safe { color: #27ae60; }
        table { width: 100%; border-collapse: collapse; margin: 20px 0; }
        th { background: #e74c3c; color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #ddd; }
        tr:hover { background: #f8f9fa; }
        .severity-badge { padding: 4px 8px; border-radius: 3px; color: white; font-weight: bold; }
        .severity-critical { background: #e74c3c; }
        .severity-high { background: #e67e22; }
        .severity-medium { background: #f39c12; }
        .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; color: #7f8c8d; font-size: 12px; }
        .no-eol { color: #27ae60; font-weight: bold; font-size: 16px; padding: 20px; text-align: center; }
    </style>
</head>
<body>
    <div class="container">
        <h1>End-of-Life Software Report</h1>
        <p><strong>Computer:</strong> $($Findings.ComputerName) | <strong>Scan Date:</strong> $($Findings.ScanDate)</p>
         
        <div class="summary">
            <h2>Summary</h2>
            <div class="metric">
                <div class="metric-label">Total Software</div>
                <div class="metric-value">$($Findings.TotalSoftware)</div>
            </div>
            <div class="metric">
                <div class="metric-label">EOL Software</div>
                <div class="metric-value $(if($Findings.Summary.TotalEOL -gt 0){'critical'}else{'safe'})">
                    $($Findings.Summary.TotalEOL)
                </div>
            </div>
            <div class="metric">
                <div class="metric-label">Critical Risk</div>
                <div class="metric-value critical">$($Findings.Summary.CriticalRisk)</div>
            </div>
            <div class="metric">
                <div class="metric-label">High Risk</div>
                <div class="metric-value high">$($Findings.Summary.HighRisk)</div>
            </div>
            <div class="metric">
                <div class="metric-label">Expiring Soon</div>
                <div class="metric-value medium">$($Findings.Summary.TotalExpiring)</div>
            </div>
        </div>
         
        <h2>End-of-Life Software</h2>
"@

    
    if ($Findings.EOLSoftware.Count -gt 0) {
        $html += @"
        <table>
            <tr>
                <th>Severity</th>
                <th>Software</th>
                <th>Version</th>
                <th>EOL Date</th>
                <th>Days Since EOL</th>
                <th>Replacement</th>
                <th>Notes</th>
            </tr>
"@

        
        foreach ($software in ($Findings.EOLSoftware | Sort-Object { 
            switch ($_.Severity) {
                'Critical' { 0 }
                'High' { 1 }
                'Medium' { 2 }
                default { 3 }
            }
        }, DaysSinceEOL -Descending)) {
            $severityClass = "severity-$($software.Severity.ToLower())"
            $name = $software.Name -replace '<', '&lt;' -replace '>', '&gt;'
            $version = "$($software.Version)" -replace '<', '&lt;' -replace '>', '&gt;'
            $replacement = $software.Replacement -replace '<', '&lt;' -replace '>', '&gt;'
            $notes = $software.Notes -replace '<', '&lt;' -replace '>', '&gt;'
            
            $html += @"
            <tr>
                <td><span class="severity-badge $severityClass">$($software.Severity)</span></td>
                <td><strong>$name</strong></td>
                <td>$version</td>
                <td>$($software.EOLDate)</td>
                <td>$($software.DaysSinceEOL)</td>
                <td>$replacement</td>
                <td>$notes</td>
            </tr>
"@

        }
        
        $html += " </table>`n"
    }
    else {
        $html += " <p class=`"no-eol`">No end-of-life software detected</p>`n"
    }
    
    if ($Findings.ExpiringSoon.Count -gt 0) {
        $html += " `n <h2>Software Expiring Soon</h2>`n <table>`n"
        $html += " <tr><th>Software</th><th>EOL Date</th><th>Days Until EOL</th><th>Replacement</th></tr>`n"
        
        foreach ($software in ($Findings.ExpiringSoon | Sort-Object DaysUntilEOL)) {
            $name = $software.Name -replace '<', '&lt;' -replace '>', '&gt;'
            $replacement = $software.Replacement -replace '<', '&lt;' -replace '>', '&gt;'
            
            $html += " <tr><td>$name</td><td>$($software.EOLDate)</td><td>$($software.DaysUntilEOL)</td><td>$replacement</td></tr>`n"
        }
        
        $html += " </table>`n"
    }
    
    $html += " `n <h2>Recommendations</h2>`n <ul>`n"
    
    foreach ($rec in $Findings.Recommendations) {
        $recEscaped = $rec -replace '<', '&lt;' -replace '>', '&gt;'
        $html += " <li>$recEscaped</li>`n"
    }
    
    $currentDate = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    
    $html += @"
        </ul>
         
        <div class="footer">
            Generated by WindowsSecurityAudit Module | EOL Software Detection | $currentDate
        </div>
    </div>
</body>
</html>
"@

    
    return $html
}