Vulnerability/Get-VulnerabilityAssessment.ps1
|
function Get-VulnerabilityAssessment { <# .SYNOPSIS Performs comprehensive vulnerability assessment of installed software .DESCRIPTION Scans installed software, checks against known vulnerabilities (CVE database), identifies security risks, and provides remediation recommendations .PARAMETER ScanDepth Scan depth: Quick (installed apps only), Standard (+ services), Deep (+ drivers) .PARAMETER IncludeCVELookup Query online CVE databases (requires internet) .PARAMETER CheckCVEs Query the NVD API 2.0 for real CVE matches per installed product (requires internet) .PARAMETER ExactCVEMatch Resolve each installed product to a CPE 2.3 name via Resolve-CpeName and query the NVD API 2.0 for version-exact CVE matches (implies -CheckCVEs behavior, requires internet). Results are attached as ExactCVEs per application and the summary gains TotalExactCVEs plus per-severity exact counts .PARAMETER NVDApiKey Optional NVD API key for higher rate limits (sent only as a request header) .PARAMETER MaxCVEChecks Maximum number of unique products to check against the NVD API (default: 10) .PARAMETER OutputPath Path to save vulnerability report .PARAMETER Format Report format: HTML, JSON, CSV, or All .EXAMPLE Get-VulnerabilityAssessment -ScanDepth Standard Get-VulnerabilityAssessment -CheckCVEs -MaxCVEChecks 5 -OutputPath "C:\Reports" .OUTPUTS PSCustomObject with vulnerability assessment results #> [CmdletBinding()] param( [Parameter()] [ValidateSet('Quick', 'Standard', 'Deep')] [string]$ScanDepth = 'Standard', [Parameter()] [switch]$IncludeCVELookup, [Parameter()] [switch]$CheckCVEs, [Parameter()] [switch]$ExactCVEMatch, [Parameter()] [string]$NVDApiKey, [Parameter()] [ValidateRange(1, 100)] [int]$MaxCVEChecks = 10, [Parameter()] [string]$OutputPath, [Parameter()] [ValidateSet('HTML', 'JSON', 'CSV', 'All')] [string]$Format = 'HTML' ) begin { Write-Host "=== VULNERABILITY ASSESSMENT ===" -ForegroundColor Cyan Write-Host "Start Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Yellow Write-Host "Scan Depth: $ScanDepth" -ForegroundColor Yellow Write-Host "CVE Lookup: $(if($CheckCVEs -or $IncludeCVELookup -or $ExactCVEMatch){'Enabled'}else{'Disabled'})" -ForegroundColor Yellow if ($CheckCVEs -or $ExactCVEMatch) { Write-Host "Max CVE Checks: $MaxCVEChecks" -ForegroundColor Yellow Write-Host "Exact CVE Match (CPE): $(if($ExactCVEMatch){'Enabled'}else{'Disabled'})" -ForegroundColor Yellow Write-Host "NVD API Key: $(if($NVDApiKey){'Provided'}else{'Not provided (public rate limits apply)'})" -ForegroundColor Yellow } $assessment = [PSCustomObject]@{ ScanDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss" ComputerName = $env:COMPUTERNAME ScanDepth = $ScanDepth Software = @() Vulnerabilities = @() Summary = @{ TotalApplications = 0 VulnerableApplications = 0 CriticalVulnerabilities = 0 HighVulnerabilities = 0 MediumVulnerabilities = 0 LowVulnerabilities = 0 } Recommendations = @() } # Known vulnerable versions database (offline fallback) $knownVulnerabilities = @{ 'Google Chrome' = @{ VulnerableVersions = @('120.0.0.0', '119.0.0.0', '118.0.0.0') LatestSafe = '121.0.6167.85' Severity = 'High' CVE = 'CVE-2024-0517, CVE-2024-0518' Description = 'Multiple security vulnerabilities including remote code execution' } 'Mozilla Firefox' = @{ VulnerableVersions = @('121.0', '120.0', '119.0') LatestSafe = '122.0' Severity = 'High' CVE = 'CVE-2024-0741, CVE-2024-0742' Description = 'Security vulnerabilities in browser engine' } 'Adobe Acrobat Reader DC' = @{ VulnerableVersions = @('23.001.20687', '23.001.20604') LatestSafe = '24.001.20643' Severity = 'Critical' CVE = 'CVE-2024-20720, CVE-2024-20721' Description = 'Arbitrary code execution vulnerabilities' } 'Java' = @{ VulnerableVersions = @('8.0.391', '8.0.381', '8.0.371') LatestSafe = '8.0.401' Severity = 'Critical' CVE = 'CVE-2024-20918, CVE-2024-20919' Description = 'Remote code execution and privilege escalation' } 'OpenSSL' = @{ VulnerableVersions = @('3.0.0', '3.0.1', '3.0.2', '3.0.3', '3.0.4', '3.0.5', '3.0.6', '3.0.7') LatestSafe = '3.0.13' Severity = 'High' CVE = 'CVE-2024-0727' Description = 'Denial of service vulnerability' } 'WinRAR' = @{ VulnerableVersions = @('6.23', '6.22', '6.21', '6.20') LatestSafe = '6.24' Severity = 'Critical' CVE = 'CVE-2023-40477' Description = 'Remote code execution via malicious archives' } } } process { try { # 1. SCAN INSTALLED SOFTWARE Write-Host "`n[1/5] Scanning installed applications..." -ForegroundColor Cyan # Get installed software from registry - FIXED: Safe property access for all properties $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) { # FIXED: Safe property check for DisplayName if ($null -ne $item.PSObject.Properties['DisplayName'] -and $null -ne $item.DisplayName -and $item.DisplayName -ne '') { # FIXED: Safe property access with fallbacks for all properties $displayVersion = if ($null -ne $item.PSObject.Properties['DisplayVersion']) { $item.DisplayVersion } else { 'Unknown' } $publisher = if ($null -ne $item.PSObject.Properties['Publisher']) { $item.Publisher } else { 'Unknown' } $installDate = if ($null -ne $item.PSObject.Properties['InstallDate']) { $item.InstallDate } else { $null } $installedSoftware += [PSCustomObject]@{ DisplayName = $item.DisplayName DisplayVersion = $displayVersion Publisher = $publisher InstallDate = $installDate } } } } } # Remove duplicates $installedSoftware = @($installedSoftware | Sort-Object DisplayName -Unique | Where-Object { $_.DisplayName -notlike "KB*" -and $_.DisplayName -notlike "Update for*" }) $assessment.Summary.TotalApplications = $installedSoftware.Count Write-Host " Found $($installedSoftware.Count) installed applications" -ForegroundColor Gray # 2. CHECK VULNERABLE VERSIONS (OFFLINE) Write-Host "`n[2/5] Checking against known vulnerabilities..." -ForegroundColor Cyan $vulnerableApps = @() foreach ($app in $installedSoftware) { $appInfo = [PSCustomObject]@{ Name = $app.DisplayName Version = $app.DisplayVersion Publisher = $app.Publisher InstallDate = $app.InstallDate IsVulnerable = $false Vulnerabilities = @() } # Check against known vulnerabilities foreach ($vulnName in $knownVulnerabilities.Keys) { if ($app.DisplayName -like "*$vulnName*") { $vulnInfo = $knownVulnerabilities[$vulnName] # Check if version is vulnerable $isVulnerable = $false if ($app.DisplayVersion -and $app.DisplayVersion -ne 'Unknown') { foreach ($vulnVersion in $vulnInfo.VulnerableVersions) { if ($app.DisplayVersion -like "$vulnVersion*") { $isVulnerable = $true break } } } if ($isVulnerable) { $appInfo.IsVulnerable = $true $vulnerability = [PSCustomObject]@{ Software = $app.DisplayName CurrentVersion = $app.DisplayVersion Severity = $vulnInfo.Severity CVE = $vulnInfo.CVE Description = $vulnInfo.Description RecommendedVersion = $vulnInfo.LatestSafe Remediation = "Update to version $($vulnInfo.LatestSafe) or later" } $appInfo.Vulnerabilities += $vulnerability $assessment.Vulnerabilities += $vulnerability # Update counters switch ($vulnInfo.Severity) { 'Critical' { $assessment.Summary.CriticalVulnerabilities++ } 'High' { $assessment.Summary.HighVulnerabilities++ } 'Medium' { $assessment.Summary.MediumVulnerabilities++ } 'Low' { $assessment.Summary.LowVulnerabilities++ } } Write-Host " [!] VULNERABLE: $($app.DisplayName) $($app.DisplayVersion) - $($vulnInfo.Severity)" -ForegroundColor Red } } } if ($appInfo.IsVulnerable) { $vulnerableApps += $appInfo $assessment.Summary.VulnerableApplications++ } $assessment.Software += $appInfo } Write-Host " Found $($assessment.Summary.VulnerableApplications) vulnerable applications" -ForegroundColor $( if ($assessment.Summary.CriticalVulnerabilities -gt 0) { 'Red' } elseif ($assessment.Summary.HighVulnerabilities -gt 0) { 'Yellow' } else { 'Gray' } ) # 3. SCAN SERVICES (if Standard or Deep) if ($ScanDepth -in @('Standard', 'Deep')) { Write-Host "`n[3/5] Scanning services..." -ForegroundColor Cyan $services = Get-Service -ErrorAction SilentlyContinue | Where-Object { $null -ne $_ -and $_.PSObject.Properties['Status'] -and $_.Status -eq 'Running' } | Select-Object Name, DisplayName, StartType # Check for potentially vulnerable services $vulnerableServiceNames = @( 'RemoteRegistry', 'TlntSvr', 'SNMP', 'RpcLocator' ) foreach ($service in $services) { if ($service.Name -in $vulnerableServiceNames) { $vulnerability = [PSCustomObject]@{ Software = "Service: $($service.DisplayName)" CurrentVersion = 'N/A' Severity = 'Medium' CVE = 'N/A' Description = "Service '$($service.Name)' is running and may pose security risks" RecommendedVersion = 'N/A' Remediation = "Disable service if not required: Stop-Service -Name '$($service.Name)' -Force" } $assessment.Vulnerabilities += $vulnerability $assessment.Summary.MediumVulnerabilities++ Write-Host " [!] Potentially risky service: $($service.Name)" -ForegroundColor Yellow } } } # 4. CVE ONLINE LOOKUP (if enabled) if ($CheckCVEs -or $IncludeCVELookup -or $ExactCVEMatch) { Write-Host "`n[4/5] Performing online CVE lookup via NVD API..." -ForegroundColor Cyan Write-Host " Note: This may take several minutes (NVD rate limits)..." -ForegroundColor Gray $assessment.Summary.TotalRealCVEs = 0 $assessment.Summary.CriticalCVEs = 0 $assessment.Summary.HighCVEs = 0 $assessment.Summary.MediumCVEs = 0 $assessment.Summary.LowCVEs = 0 if ($ExactCVEMatch) { $assessment.Summary.TotalExactCVEs = 0 $assessment.Summary.CriticalExactCVEs = 0 $assessment.Summary.HighExactCVEs = 0 $assessment.Summary.MediumExactCVEs = 0 $assessment.Summary.LowExactCVEs = 0 } $nvdParams = @{} if ($NVDApiKey) { $nvdParams['ApiKey'] = $NVDApiKey } $nvdSleepSeconds = if ($NVDApiKey) { 0.6 } else { 6 } $uniqueProducts = @($assessment.Software | Sort-Object Name -Unique | Select-Object -First $MaxCVEChecks) $checkedApps = 0 foreach ($app in $uniqueProducts) { try { $keywordParts = @() if ($app.Publisher -and $app.Publisher -ne 'Unknown') { $keywordParts += $app.Publisher } if ($app.Name) { $keywordParts += $app.Name } if ($keywordParts.Count -eq 0) { continue } $searchKeyword = ($keywordParts -join ' ') -replace '\s+', ' ' if ($checkedApps -gt 0) { Start-Sleep -Seconds $nvdSleepSeconds } $checkedApps++ Write-Host " Checking CVEs for: $searchKeyword..." -ForegroundColor Gray $realCVEs = @(Get-NVDCveData -Keyword $searchKeyword @nvdParams) $app | Add-Member -NotePropertyName RealCVEs -NotePropertyValue $realCVEs -Force foreach ($cve in $realCVEs) { $assessment.Summary.TotalRealCVEs++ if ($null -ne $cve.PSObject.Properties['Severity'] -and $null -ne $cve.Severity) { switch ($cve.Severity) { 'Critical' { $assessment.Summary.CriticalCVEs++ } 'High' { $assessment.Summary.HighCVEs++ } 'Medium' { $assessment.Summary.MediumCVEs++ } 'Low' { $assessment.Summary.LowCVEs++ } } } } if ($realCVEs.Count -gt 0) { Write-Host " Found $($realCVEs.Count) real CVE(s)" -ForegroundColor Yellow } if ($ExactCVEMatch) { try { $resolveParams = @{ ProductName = $app.Name } if ($app.Publisher -and $app.Publisher -ne 'Unknown') { $resolveParams['Vendor'] = $app.Publisher } if ($app.Version -and $app.Version -ne 'Unknown') { $resolveParams['Version'] = $app.Version } if ($NVDApiKey) { $resolveParams['UseOnlineLookup'] = $true $resolveParams['ApiKey'] = $NVDApiKey } $cpeResolution = Resolve-CpeName @resolveParams $app | Add-Member -NotePropertyName CpeResolution -NotePropertyValue $cpeResolution -Force $hasUsableCpe = $false if ($null -ne $cpeResolution -and $null -ne $cpeResolution.PSObject.Properties['CpeName'] -and $null -ne $cpeResolution.CpeName -and $null -ne $cpeResolution.PSObject.Properties['Confidence'] -and $cpeResolution.Confidence -in @('High', 'Medium')) { $hasUsableCpe = $true } if ($hasUsableCpe) { $app | Add-Member -NotePropertyName MatchStatus -NotePropertyValue 'CpeMatched' -Force Start-Sleep -Seconds $nvdSleepSeconds Write-Host " Checking exact CVEs for CPE: $($cpeResolution.CpeName)..." -ForegroundColor Gray $exactCVEs = @(Get-NVDCveData -CpeName $cpeResolution.CpeName @nvdParams) $app | Add-Member -NotePropertyName ExactCVEs -NotePropertyValue $exactCVEs -Force foreach ($cve in $exactCVEs) { $assessment.Summary.TotalExactCVEs++ if ($null -ne $cve.PSObject.Properties['Severity'] -and $null -ne $cve.Severity) { switch ($cve.Severity) { 'Critical' { $assessment.Summary.CriticalExactCVEs++ } 'High' { $assessment.Summary.HighExactCVEs++ } 'Medium' { $assessment.Summary.MediumExactCVEs++ } 'Low' { $assessment.Summary.LowExactCVEs++ } } } } if ($exactCVEs.Count -gt 0) { Write-Host " Found $($exactCVEs.Count) exact CVE(s)" -ForegroundColor Yellow } } else { $app | Add-Member -NotePropertyName MatchStatus -NotePropertyValue 'NoCpeMapping' -Force Write-Host " No reliable CPE mapping for: $($app.Name)" -ForegroundColor Gray } } catch { Write-Warning "Could not resolve CPE for $($app.Name): $_" if ($null -eq $app.PSObject.Properties['MatchStatus']) { $app | Add-Member -NotePropertyName MatchStatus -NotePropertyValue 'NoCpeMapping' -Force } } } } catch { Write-Warning "Could not check CVEs for $($app.Name): $_" } } if ($assessment.Summary.TotalRealCVEs -gt 0) { $assessment.Recommendations += "NVD: $($assessment.Summary.TotalRealCVEs) real CVE(s) matched installed software - review RealCVEs details per application" } if ($ExactCVEMatch -and $assessment.Summary.TotalExactCVEs -gt 0) { $assessment.Recommendations += "NVD (exact/CPE): $($assessment.Summary.TotalExactCVEs) version-exact CVE(s) confirmed against installed versions - prioritize these for patching" } Write-Host " Checked $checkedApps application(s) against NVD, matched $($assessment.Summary.TotalRealCVEs) real CVE(s)" -ForegroundColor Gray if ($ExactCVEMatch) { Write-Host " Matched $($assessment.Summary.TotalExactCVEs) version-exact CVE(s) via CPE" -ForegroundColor Gray } } else { Write-Host "`n[4/5] Skipping online CVE lookup (disabled)" -ForegroundColor Gray } # 5. GENERATE RECOMMENDATIONS Write-Host "`n[5/5] Generating recommendations..." -ForegroundColor Cyan if ($assessment.Summary.CriticalVulnerabilities -gt 0) { $assessment.Recommendations += "CRITICAL: $($assessment.Summary.CriticalVulnerabilities) critical vulnerability(ies) detected - patch immediately" } if ($assessment.Summary.HighVulnerabilities -gt 0) { $assessment.Recommendations += "HIGH: $($assessment.Summary.HighVulnerabilities) high-severity vulnerability(ies) - patch within 7 days" } if ($assessment.Summary.MediumVulnerabilities -gt 0) { $assessment.Recommendations += "MEDIUM: $($assessment.Summary.MediumVulnerabilities) medium-severity vulnerability(ies) - patch within 30 days" } if ($assessment.Summary.VulnerableApplications -eq 0) { $assessment.Recommendations += "No known vulnerabilities detected in installed software" } $assessment.Recommendations += "Enable automatic updates where possible" $assessment.Recommendations += "Implement vulnerability scanning schedule (weekly recommended)" $assessment.Recommendations += "Subscribe to vendor security bulletins" $assessment.Recommendations += "Consider implementing application whitelisting" # 6. EXPORT REPORTS if ($OutputPath) { Write-Host "`n[*] Exporting vulnerability reports..." -ForegroundColor Cyan if (-not (Test-Path $OutputPath)) { New-Item -Path $OutputPath -ItemType Directory -Force | Out-Null } $timestamp = Get-Date -Format "yyyyMMdd_HHmmss" $reportName = "VulnerabilityAssessment_$timestamp" # Export JSON if ($Format -in @('JSON', 'All')) { $jsonPath = Join-Path $OutputPath "$reportName.json" $assessment | ConvertTo-Json -Depth 10 | Out-File $jsonPath -Encoding UTF8 Write-Host " JSON report saved: $jsonPath" -ForegroundColor Green } # Export CSV (Vulnerabilities) if ($Format -in @('CSV', 'All')) { $csvPath = Join-Path $OutputPath "$reportName.csv" $assessment.Vulnerabilities | 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-VulnerabilityHTML -Assessment $assessment $html | Out-File $htmlPath -Encoding UTF8 Write-Host " HTML report saved: $htmlPath" -ForegroundColor Green } } } catch { Write-Error "Error during vulnerability assessment: $_" throw } } end { Write-Host "`n=== VULNERABILITY ASSESSMENT COMPLETE ===" -ForegroundColor $( if ($assessment.Summary.CriticalVulnerabilities -gt 0) { 'Red' } elseif ($assessment.Summary.HighVulnerabilities -gt 0) { 'Yellow' } else { 'Green' } ) Write-Host "`nSummary:" -ForegroundColor Cyan Write-Host " Total Applications: $($assessment.Summary.TotalApplications)" -ForegroundColor White Write-Host " Vulnerable Applications: $($assessment.Summary.VulnerableApplications)" -ForegroundColor $( if ($assessment.Summary.VulnerableApplications -gt 0) { 'Yellow' } else { 'Green' } ) Write-Host " Critical Vulnerabilities: $($assessment.Summary.CriticalVulnerabilities)" -ForegroundColor $( if ($assessment.Summary.CriticalVulnerabilities -gt 0) { 'Red' } else { 'Gray' } ) Write-Host " High Vulnerabilities: $($assessment.Summary.HighVulnerabilities)" -ForegroundColor $( if ($assessment.Summary.HighVulnerabilities -gt 0) { 'Yellow' } else { 'Gray' } ) Write-Host " Medium Vulnerabilities: $($assessment.Summary.MediumVulnerabilities)" -ForegroundColor Gray Write-Host " Low Vulnerabilities: $($assessment.Summary.LowVulnerabilities)" -ForegroundColor Gray if ($assessment.Summary.ContainsKey('TotalRealCVEs')) { Write-Host " Real CVEs (NVD): $($assessment.Summary.TotalRealCVEs)" -ForegroundColor $( if ($assessment.Summary.TotalRealCVEs -gt 0) { 'Yellow' } else { 'Gray' } ) Write-Host " Critical CVEs (NVD): $($assessment.Summary.CriticalCVEs)" -ForegroundColor $( if ($assessment.Summary.CriticalCVEs -gt 0) { 'Red' } else { 'Gray' } ) Write-Host " High CVEs (NVD): $($assessment.Summary.HighCVEs)" -ForegroundColor $( if ($assessment.Summary.HighCVEs -gt 0) { 'Yellow' } else { 'Gray' } ) } if ($assessment.Summary.ContainsKey('TotalExactCVEs')) { Write-Host " Exact CVEs (NVD/CPE): $($assessment.Summary.TotalExactCVEs)" -ForegroundColor $( if ($assessment.Summary.TotalExactCVEs -gt 0) { 'Yellow' } else { 'Gray' } ) Write-Host " Critical Exact CVEs: $($assessment.Summary.CriticalExactCVEs)" -ForegroundColor $( if ($assessment.Summary.CriticalExactCVEs -gt 0) { 'Red' } else { 'Gray' } ) Write-Host " High Exact CVEs: $($assessment.Summary.HighExactCVEs)" -ForegroundColor $( if ($assessment.Summary.HighExactCVEs -gt 0) { 'Yellow' } else { 'Gray' } ) } if ($assessment.Vulnerabilities.Count -gt 0) { Write-Host "`nTop Vulnerabilities:" -ForegroundColor Cyan $assessment.Vulnerabilities | Sort-Object { switch ($_.Severity) { 'Critical' { 0 } 'High' { 1 } 'Medium' { 2 } 'Low' { 3 } } } | Select-Object -First 5 | ForEach-Object { Write-Host " [$($_.Severity)] $($_.Software) - $($_.CVE)" -ForegroundColor $( switch ($_.Severity) { 'Critical' { 'Red' } 'High' { 'Yellow' } default { 'Gray' } } ) } } if ($assessment.Recommendations.Count -gt 0) { Write-Host "`nRecommendations:" -ForegroundColor Cyan $assessment.Recommendations | ForEach-Object { Write-Host " ! $_" -ForegroundColor Yellow } } return $assessment } } # Helper function to generate HTML report function Generate-VulnerabilityHTML { param($Assessment) $vulnColor = if($Assessment.Summary.VulnerableApplications -gt 0){'critical'}else{'safe'} $html = @" <!DOCTYPE html> <html> <head> <title>Vulnerability Assessment - $($Assessment.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; } .severity-low { background: #95a5a6; } .footer { margin-top: 40px; padding-top: 20px; border-top: 1px solid #ddd; color: #7f8c8d; font-size: 12px; } .no-vuln { color: #27ae60; font-weight: bold; font-size: 16px; padding: 20px; text-align: center; } </style> </head> <body> <div class="container"> <h1>Vulnerability Assessment Report</h1> <p><strong>Computer:</strong> $($Assessment.ComputerName) | <strong>Scan Date:</strong> $($Assessment.ScanDate)</p> <p><strong>Scan Depth:</strong> $($Assessment.ScanDepth)</p> <div class="summary"> <h2>Executive Summary</h2> <div class="metric"> <div class="metric-label">Total Applications</div> <div class="metric-value">$($Assessment.Summary.TotalApplications)</div> </div> <div class="metric"> <div class="metric-label">Vulnerable Applications</div> <div class="metric-value $vulnColor"> $($Assessment.Summary.VulnerableApplications) </div> </div> <div class="metric"> <div class="metric-label">Critical</div> <div class="metric-value critical">$($Assessment.Summary.CriticalVulnerabilities)</div> </div> <div class="metric"> <div class="metric-label">High</div> <div class="metric-value high">$($Assessment.Summary.HighVulnerabilities)</div> </div> <div class="metric"> <div class="metric-label">Medium</div> <div class="metric-value medium">$($Assessment.Summary.MediumVulnerabilities)</div> </div> </div> <h2>Detected Vulnerabilities</h2> "@ if ($Assessment.Vulnerabilities.Count -gt 0) { $html += @" <table> <tr> <th>Severity</th> <th>Software</th> <th>Current Version</th> <th>CVE</th> <th>Description</th> <th>Remediation</th> </tr> "@ foreach ($vuln in ($Assessment.Vulnerabilities | Sort-Object { switch ($_.Severity) { 'Critical' { 0 } 'High' { 1 } 'Medium' { 2 } 'Low' { 3 } } })) { $severityClass = "severity-$($vuln.Severity.ToLower())" $software = $vuln.Software -replace '<', '<' -replace '>', '>' $desc = $vuln.Description -replace '<', '<' -replace '>', '>' $rem = $vuln.Remediation -replace '<', '<' -replace '>', '>' $html += @" <tr> <td><span class="severity-badge $severityClass">$($vuln.Severity)</span></td> <td><strong>$software</strong></td> <td>$($vuln.CurrentVersion)</td> <td>$($vuln.CVE)</td> <td>$desc</td> <td>$rem</td> </tr> "@ } $html += " </table>`n" } else { $html += " <p class=`"no-vuln`">No known vulnerabilities detected</p>`n" } $html += " `n <h2>Recommendations</h2>`n <ul>`n" foreach ($rec in $Assessment.Recommendations) { $recEscaped = $rec -replace '<', '<' -replace '>', '>' $html += " <li>$recEscaped</li>`n" } $currentDate = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' $html += @" </ul> <div class="footer"> Generated by WindowsSecurityAudit Module | Vulnerability Assessment | $currentDate </div> </div> </body> </html> "@ return $html } |