Vulnerability/Test-CertificateHealth.ps1

function Test-CertificateHealth {
    <#
    .SYNOPSIS
        Tests certificate health and identifies expiring or invalid certificates
    .DESCRIPTION
        Scans system certificates, identifies expired, expiring, weak, or invalid
        certificates across multiple certificate stores. Provides detailed findings
        with remediation steps for certificate management.
    .PARAMETER ExpiringDays
        Number of days to check for expiring certificates (default: 30)
    .PARAMETER IncludeUserStore
        Include current user certificate store in scan
    .PARAMETER CheckRevocation
        Check certificate revocation status (slower)
    .PARAMETER OutputPath
        Path to save certificate health report
    .PARAMETER Format
        Report format: HTML, JSON, CSV, or All
    .EXAMPLE
        Test-CertificateHealth
        Test-CertificateHealth -ExpiringDays 60 -IncludeUserStore -OutputPath "C:\Reports"
    .OUTPUTS
        PSCustomObject with certificate health findings
    #>

    
    [CmdletBinding()]
    param(
        [Parameter()]
        [int]$ExpiringDays = 30,
        
        [Parameter()]
        [switch]$IncludeUserStore,
        
        [Parameter()]
        [switch]$CheckRevocation,
        
        [Parameter()]
        [string]$OutputPath,
        
        [Parameter()]
        [ValidateSet('HTML', 'JSON', 'CSV', 'All')]
        [string]$Format = 'HTML'
    )
    
    begin {
        Write-Host "=== CERTIFICATE HEALTH CHECK ===" -ForegroundColor Cyan
        Write-Host "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Yellow
        Write-Host "Expiring Threshold: $ExpiringDays days" -ForegroundColor Yellow
        Write-Host "Include User Store: $(if($IncludeUserStore){'Yes'}else{'No'})" -ForegroundColor Yellow
        Write-Host "Check Revocation: $(if($CheckRevocation){'Yes'}else{'No'})" -ForegroundColor Yellow
        
        $results = [PSCustomObject]@{
            ScanDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            ComputerName = $env:COMPUTERNAME
            TotalCertificates = 0
            HealthyCertificates = 0
            Issues = @()
            Summary = @{
                Expired = 0
                ExpiringSoon = 0
                SelfSigned = 0
                WeakSignature = 0
                Revoked = 0
                InvalidChain = 0
                DuplicateThumbprints = 0
            }
            Recommendations = @()
        }
        
        # Weak signature algorithms
        $weakAlgorithms = @('md5', 'sha1')
    }
    
    process {
        try {
            # Define certificate stores to scan
            $storesToScan = @(
                @{Location='LocalMachine'; Stores=@('My', 'Root', 'CA', 'TrustedPublisher', 'WebHosting')}
            )
            
            if ($IncludeUserStore) {
                $storesToScan += @{Location='CurrentUser'; Stores=@('My', 'Root', 'CA', 'TrustedPublisher')}
            }
            
            Write-Host "`n[1/3] Scanning certificate stores..." -ForegroundColor Cyan
            
            $allCertificates = @()
            $currentDate = Get-Date
            $expiringThreshold = $currentDate.AddDays($ExpiringDays)
            
            foreach ($storeConfig in $storesToScan) {
                $location = $storeConfig.Location
                
                foreach ($storeName in $storeConfig.Stores) {
                    try {
                        Write-Host " Scanning: $location\$storeName..." -ForegroundColor Gray
                        
                        $store = New-Object System.Security.Cryptography.X509Certificates.X509Store($storeName, $location)
                        $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
                        
                        $certificates = $store.Certificates
                        
                        foreach ($cert in $certificates) {
                            $certInfo = [PSCustomObject]@{
                                Store = "$location\$storeName"
                                Subject = $cert.Subject
                                Issuer = $cert.Issuer
                                Thumbprint = $cert.Thumbprint
                                NotBefore = $cert.NotBefore
                                NotAfter = $cert.NotAfter
                                SignatureAlgorithm = $cert.SignatureAlgorithm.FriendlyName
                                HasPrivateKey = $cert.HasPrivateKey
                                IsSelfSigned = ($cert.Subject -eq $cert.Issuer)
                                Status = 'Healthy'
                            }
                            
                            $allCertificates += $certInfo
                        }
                        
                        $store.Close()
                    }
                    catch {
                        # FIXED: Remove colon from warning message
                        Write-Warning "Could not access store $location\$storeName - $_"
                    }
                }
            }
            
            $results.TotalCertificates = $allCertificates.Count
            Write-Host " Found $($allCertificates.Count) certificates" -ForegroundColor Green
            
            # 2. ANALYZE CERTIFICATES
            Write-Host "`n[2/3] Analyzing certificates..." -ForegroundColor Cyan
            
            # Check for expired certificates
            $expired = $allCertificates | Where-Object { $_.NotAfter -lt $currentDate }
            foreach ($cert in $expired) {
                $daysExpired = [Math]::Round(($currentDate - $cert.NotAfter).TotalDays)
                
                $results.Issues += [PSCustomObject]@{
                    Severity = 'High'
                    Category = 'Expired'
                    Certificate = $cert.Subject
                    Store = $cert.Store
                    Thumbprint = $cert.Thumbprint
                    Issue = "Certificate expired $daysExpired days ago"
                    NotAfter = $cert.NotAfter.ToString('yyyy-MM-dd')
                    Remediation = "Remove expired certificate or renew - Remove-Item Cert:\$($cert.Store)\$($cert.Thumbprint)"
                }
                
                $results.Summary.Expired++
                Write-Host " [!] HIGH: Expired certificate - $($cert.Subject)" -ForegroundColor Yellow
            }
            
            # Check for expiring certificates
            $expiring = $allCertificates | Where-Object { 
                $_.NotAfter -gt $currentDate -and 
                $_.NotAfter -le $expiringThreshold 
            }
            
            foreach ($cert in $expiring) {
                $daysUntilExpiry = [Math]::Round(($cert.NotAfter - $currentDate).TotalDays)
                
                $results.Issues += [PSCustomObject]@{
                    Severity = if($daysUntilExpiry -le 7){'High'}elseif($daysUntilExpiry -le 14){'Medium'}else{'Low'}
                    Category = 'Expiring Soon'
                    Certificate = $cert.Subject
                    Store = $cert.Store
                    Thumbprint = $cert.Thumbprint
                    Issue = "Certificate expires in $daysUntilExpiry days"
                    NotAfter = $cert.NotAfter.ToString('yyyy-MM-dd')
                    Remediation = "Renew certificate before expiration"
                }
                
                $results.Summary.ExpiringSoon++
                
                $color = if($daysUntilExpiry -le 7){'Yellow'}else{'Gray'}
                Write-Host " [*] Expiring: $($cert.Subject) - $daysUntilExpiry days" -ForegroundColor $color
            }
            
            # Check for self-signed certificates in sensitive stores
            $sensitiveStores = @('LocalMachine\My', 'LocalMachine\WebHosting')
            $selfSignedInSensitive = $allCertificates | Where-Object { 
                $_.IsSelfSigned -and 
                $_.Store -in $sensitiveStores 
            }
            
            foreach ($cert in $selfSignedInSensitive) {
                $results.Issues += [PSCustomObject]@{
                    Severity = 'Medium'
                    Category = 'Self-Signed'
                    Certificate = $cert.Subject
                    Store = $cert.Store
                    Thumbprint = $cert.Thumbprint
                    Issue = "Self-signed certificate in production store"
                    NotAfter = $cert.NotAfter.ToString('yyyy-MM-dd')
                    Remediation = "Replace with CA-issued certificate for production use"
                }
                
                $results.Summary.SelfSigned++
                Write-Host " [*] Self-signed certificate: $($cert.Subject)" -ForegroundColor Gray
            }
            
            # Check for weak signature algorithms
            foreach ($cert in $allCertificates) {
                $isWeak = $false
                foreach ($weakAlg in $weakAlgorithms) {
                    if ($cert.SignatureAlgorithm -like "*$weakAlg*") {
                        $isWeak = $true
                        break
                    }
                }
                
                if ($isWeak) {
                    $results.Issues += [PSCustomObject]@{
                        Severity = 'High'
                        Category = 'Weak Signature'
                        Certificate = $cert.Subject
                        Store = $cert.Store
                        Thumbprint = $cert.Thumbprint
                        Issue = "Uses weak signature algorithm - $($cert.SignatureAlgorithm)"
                        NotAfter = $cert.NotAfter.ToString('yyyy-MM-dd')
                        Remediation = "Replace with certificate using SHA-256 or stronger"
                    }
                    
                    $results.Summary.WeakSignature++
                    Write-Host " [!] HIGH: Weak signature - $($cert.Subject) ($($cert.SignatureAlgorithm))" -ForegroundColor Yellow
                }
            }
            
            # Check for duplicate thumbprints across stores
            $thumbprintGroups = $allCertificates | Group-Object Thumbprint | Where-Object { $_.Count -gt 1 }
            foreach ($group in $thumbprintGroups) {
                $duplicates = $group.Group
                $stores = ($duplicates | Select-Object -ExpandProperty Store) -join ', '
                
                $results.Issues += [PSCustomObject]@{
                    Severity = 'Low'
                    Category = 'Duplicate'
                    Certificate = $duplicates[0].Subject
                    Store = $stores
                    Thumbprint = $group.Name
                    Issue = "Certificate duplicated in $($group.Count) stores"
                    NotAfter = $duplicates[0].NotAfter.ToString('yyyy-MM-dd')
                    Remediation = "Review and remove unnecessary duplicates"
                }
                
                $results.Summary.DuplicateThumbprints++
            }
            
            # Check certificate chain validity (for LocalMachine\My)
            Write-Host " Validating certificate chains..." -ForegroundColor Gray
            
            $myStoreCerts = $allCertificates | Where-Object { 
                $_.Store -eq 'LocalMachine\My' -and 
                $_.NotAfter -gt $currentDate 
            }
            
            foreach ($certInfo in $myStoreCerts) {
                try {
                    $store = New-Object System.Security.Cryptography.X509Certificates.X509Store('My', 'LocalMachine')
                    $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]::ReadOnly)
                    
                    $cert = $store.Certificates | Where-Object { $_.Thumbprint -eq $certInfo.Thumbprint } | Select-Object -First 1
                    
                    if ($cert) {
                        $chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
                        $chain.ChainPolicy.RevocationMode = if($CheckRevocation){
                            [System.Security.Cryptography.X509Certificates.X509RevocationMode]::Online
                        } else {
                            [System.Security.Cryptography.X509Certificates.X509RevocationMode]::NoCheck
                        }
                        
                        $isValid = $chain.Build($cert)
                        
                        if (-not $isValid) {
                            $chainErrors = $chain.ChainStatus | ForEach-Object { $_.StatusInformation } | Select-Object -Unique
                            $errorMsg = $chainErrors -join '; '
                            
                            # Check if it's a revocation error
                            if ($CheckRevocation -and $errorMsg -match 'revok') {
                                $results.Issues += [PSCustomObject]@{
                                    Severity = 'Critical'
                                    Category = 'Revoked'
                                    Certificate = $certInfo.Subject
                                    Store = $certInfo.Store
                                    Thumbprint = $certInfo.Thumbprint
                                    Issue = "Certificate has been revoked"
                                    NotAfter = $certInfo.NotAfter.ToString('yyyy-MM-dd')
                                    Remediation = "Remove revoked certificate immediately and replace"
                                }
                                
                                $results.Summary.Revoked++
                                Write-Host " [!] CRITICAL: Revoked certificate - $($certInfo.Subject)" -ForegroundColor Red
                            }
                            else {
                                $results.Issues += [PSCustomObject]@{
                                    Severity = 'Medium'
                                    Category = 'Invalid Chain'
                                    Certificate = $certInfo.Subject
                                    Store = $certInfo.Store
                                    Thumbprint = $certInfo.Thumbprint
                                    Issue = "Certificate chain validation failed - $errorMsg"
                                    NotAfter = $certInfo.NotAfter.ToString('yyyy-MM-dd')
                                    Remediation = "Install intermediate CA certificates or verify root CA trust"
                                }
                                
                                $results.Summary.InvalidChain++
                            }
                        }
                        
                        $chain.Dispose()
                    }
                    
                    $store.Close()
                }
                catch {
                    Write-Warning "Could not validate chain for $($certInfo.Subject) - $_"
                }
            }
            
            # Count distinct unhealthy certificates: a certificate can raise several
            # issues (e.g. expired AND weak signature), so Total - Issues.Count can
            # go negative. 'Duplicate' issues are not a health problem.
            $unhealthyCertificates = @($results.Issues |
                Where-Object { $_.Category -ne 'Duplicate' } |
                ForEach-Object { "$($_.Store)|$($_.Thumbprint)" } |
                Select-Object -Unique)
            $results.HealthyCertificates = [Math]::Max(0, $results.TotalCertificates - $unhealthyCertificates.Count)
            
            # 3. GENERATE RECOMMENDATIONS
            Write-Host "`n[3/3] Generating recommendations..." -ForegroundColor Cyan
            
            if ($results.Summary.Revoked -gt 0) {
                $results.Recommendations += "CRITICAL: Remove $($results.Summary.Revoked) revoked certificate(s) immediately"
            }
            
            if ($results.Summary.Expired -gt 0) {
                $results.Recommendations += "HIGH: Remove or renew $($results.Summary.Expired) expired certificate(s)"
            }
            
            if ($results.Summary.WeakSignature -gt 0) {
                $results.Recommendations += "HIGH: Replace $($results.Summary.WeakSignature) certificate(s) using weak signature algorithms"
            }
            
            if ($results.Summary.ExpiringSoon -gt 0) {
                $results.Recommendations += "Plan renewal for $($results.Summary.ExpiringSoon) expiring certificate(s)"
            }
            
            if ($results.Summary.InvalidChain -gt 0) {
                $results.Recommendations += "Fix certificate chain issues for $($results.Summary.InvalidChain) certificate(s)"
            }
            
            if ($results.Summary.SelfSigned -gt 0) {
                $results.Recommendations += "Replace self-signed certificates with CA-issued certificates for production"
            }
            
            if ($results.Issues.Count -eq 0) {
                $results.Recommendations += "All certificates are healthy - maintain regular monitoring"
            }
            
            $results.Recommendations += "Implement automated certificate renewal (e.g., ACME/Let's Encrypt)"
            $results.Recommendations += "Set up certificate expiration alerts (60, 30, 14, 7 days)"
            $results.Recommendations += "Enable certificate revocation checking in production"
            $results.Recommendations += "Document certificate inventory and ownership"
            $results.Recommendations += "Remove unused and expired certificates quarterly"
            
            # 4. EXPORT REPORTS
            if ($OutputPath) {
                Write-Host "`n[*] Exporting certificate health reports..." -ForegroundColor Cyan
                
                if (-not (Test-Path $OutputPath)) {
                    New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null
                }
                
                $timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
                $reportName = "CertificateHealth_$timestamp"
                
                # Export JSON
                if ($Format -in @('JSON', 'All')) {
                    $jsonPath = Join-Path $OutputPath "$reportName.json"
                    $results | 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"
                    $results.Issues | 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-CertificateHealthHTML -Results $results
                    $html | Out-File $htmlPath -Encoding UTF8
                    Write-Host " HTML report saved: $htmlPath" -ForegroundColor Green
                }
            }
            
        }
        catch {
            Write-Error "Error during certificate health check: $_"
            throw
        }
    }
    
    end {
        Write-Host "`n=== CERTIFICATE HEALTH CHECK COMPLETE ===" -ForegroundColor $(
            if ($results.Summary.Revoked -gt 0) { 'Red' }
            elseif ($results.Summary.Expired -gt 0 -or $results.Summary.WeakSignature -gt 0) { 'Yellow' }
            else { 'Green' }
        )
        
        Write-Host "`nSummary:" -ForegroundColor Cyan
        Write-Host " Total Certificates: $($results.TotalCertificates)" -ForegroundColor White
        Write-Host " Healthy: $($results.HealthyCertificates)" -ForegroundColor Green
        Write-Host " Issues Found: $($results.Issues.Count)" -ForegroundColor $(
            if ($results.Issues.Count -gt 0) { 'Yellow' } else { 'Green' }
        )
        
        if ($results.Summary.Revoked -gt 0) {
            Write-Host " Revoked: $($results.Summary.Revoked)" -ForegroundColor Red
        }
        if ($results.Summary.Expired -gt 0) {
            Write-Host " Expired: $($results.Summary.Expired)" -ForegroundColor Yellow
        }
        if ($results.Summary.ExpiringSoon -gt 0) {
            Write-Host " Expiring Soon: $($results.Summary.ExpiringSoon)" -ForegroundColor Yellow
        }
        if ($results.Summary.WeakSignature -gt 0) {
            Write-Host " Weak Signatures: $($results.Summary.WeakSignature)" -ForegroundColor Yellow
        }
        if ($results.Summary.InvalidChain -gt 0) {
            Write-Host " Invalid Chains: $($results.Summary.InvalidChain)" -ForegroundColor Gray
        }
        if ($results.Summary.SelfSigned -gt 0) {
            Write-Host " Self-Signed: $($results.Summary.SelfSigned)" -ForegroundColor Gray
        }
        
        if ($results.Issues.Count -gt 0) {
            Write-Host "`nTop Issues:" -ForegroundColor Cyan
            $results.Issues | 
                Sort-Object { 
                    switch ($_.Severity) {
                        'Critical' { 0 }
                        'High' { 1 }
                        'Medium' { 2 }
                        'Low' { 3 }
                    }
                } |
                Select-Object -First 10 |
                ForEach-Object {
                    $color = switch ($_.Severity) {
                        'Critical' { 'Red' }
                        'High' { 'Yellow' }
                        default { 'Gray' }
                    }
                    Write-Host " [$($_.Severity)] $($_.Category) - $($_.Certificate)" -ForegroundColor $color
                }
        }
        
        if ($results.Recommendations.Count -gt 0) {
            Write-Host "`nRecommendations:" -ForegroundColor Cyan
            $results.Recommendations | ForEach-Object {
                Write-Host " ! $_" -ForegroundColor Yellow
            }
        }
        
        return $results
    }
}

# Helper function to generate HTML report
function Generate-CertificateHealthHTML {
    param($Results)
    
    $healthColor = if($Results.Summary.Revoked -gt 0){'critical'}
                   elseif($Results.Summary.Expired -gt 0 -or $Results.Summary.WeakSignature -gt 0){'high'}
                   else{'safe'}
    
    $html = @"
<!DOCTYPE html>
<html>
<head>
    <title>Certificate Health Report - $($Results.ComputerName)</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
        .container { max-width: 1400px; 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 #3498db; 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; font-size: 13px; }
        th { background: #3498db; color: white; padding: 10px; text-align: left; }
        td { padding: 8px; border-bottom: 1px solid #ddd; vertical-align: top; }
        tr:hover { background: #f8f9fa; }
        .severity-badge { padding: 3px 6px; border-radius: 3px; color: white; font-weight: bold; font-size: 11px; }
        .severity-critical { background: #e74c3c; }
        .severity-high { background: #e67e22; }
        .severity-medium { background: #f39c12; }
        .severity-low { background: #95a5a6; }
        .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; color: #7f8c8d; font-size: 12px; }
        .no-issues { color: #27ae60; font-weight: bold; font-size: 16px; padding: 20px; text-align: center; }
        .thumbprint { font-family: monospace; font-size: 11px; color: #7f8c8d; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Certificate Health Report</h1>
        <p><strong>Computer:</strong> $($Results.ComputerName) | <strong>Scan Date:</strong> $($Results.ScanDate)</p>
         
        <div class="summary">
            <h2>Summary</h2>
            <div class="metric">
                <div class="metric-label">Total Certificates</div>
                <div class="metric-value">$($Results.TotalCertificates)</div>
            </div>
            <div class="metric">
                <div class="metric-label">Healthy</div>
                <div class="metric-value safe">$($Results.HealthyCertificates)</div>
            </div>
            <div class="metric">
                <div class="metric-label">Issues</div>
                <div class="metric-value $(if($Results.Issues.Count -gt 0){'high'}else{'safe'})">
                    $($Results.Issues.Count)
                </div>
            </div>
            <div class="metric">
                <div class="metric-label">Expired</div>
                <div class="metric-value high">$($Results.Summary.Expired)</div>
            </div>
            <div class="metric">
                <div class="metric-label">Expiring Soon</div>
                <div class="metric-value medium">$($Results.Summary.ExpiringSoon)</div>
            </div>
            <div class="metric">
                <div class="metric-label">Weak Signature</div>
                <div class="metric-value high">$($Results.Summary.WeakSignature)</div>
            </div>
        </div>
         
        <h2>Certificate Issues</h2>
"@

    
    if ($Results.Issues.Count -gt 0) {
        $html += @"
        <table>
            <tr>
                <th style="width: 70px;">Severity</th>
                <th style="width: 100px;">Category</th>
                <th style="width: 250px;">Certificate</th>
                <th style="width: 150px;">Store</th>
                <th style="width: 100px;">Expires</th>
                <th>Issue</th>
                <th>Remediation</th>
            </tr>
"@

        
        foreach ($issue in ($Results.Issues | Sort-Object { 
            switch ($_.Severity) {
                'Critical' { 0 }
                'High' { 1 }
                'Medium' { 2 }
                'Low' { 3 }
            }
        })) {
            $severityClass = "severity-$($issue.Severity.ToLower())"
            $cert = $issue.Certificate -replace '<', '&lt;' -replace '>', '&gt;'
            $issueText = $issue.Issue -replace '<', '&lt;' -replace '>', '&gt;'
            $remediation = $issue.Remediation -replace '<', '&lt;' -replace '>', '&gt;'
            
            $thumbShort = if($issue.Thumbprint.Length -gt 16) { 
                $issue.Thumbprint.Substring(0,16) + '...' 
            } else { 
                $issue.Thumbprint 
            }
            
            $html += @"
            <tr>
                <td><span class="severity-badge $severityClass">$($issue.Severity)</span></td>
                <td>$($issue.Category)</td>
                <td><strong>$cert</strong><br><span class="thumbprint">$thumbShort</span></td>
                <td><small>$($issue.Store)</small></td>
                <td>$($issue.NotAfter)</td>
                <td>$issueText</td>
                <td><small>$remediation</small></td>
            </tr>
"@

        }
        
        $html += " </table>`n"
    }
    else {
        $html += " <p class=`"no-issues`">All certificates are healthy</p>`n"
    }
    
    $html += " `n <h2>Recommendations</h2>`n <ul>`n"
    
    foreach ($rec in $Results.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 | Certificate Health Check | $currentDate
        </div>
    </div>
</body>
</html>
"@

    
    return $html
}