Fix-SpeculativeMitigations.Tests.ps1
|
<# .SYNOPSIS Pester tests for Fix-SpeculativeMitigations.ps1 .DESCRIPTION Author: Krishnaramanan.S License: No restriction in use or modify Tested in Dev Environment only. Test this module in your Dev Environment first before using in Production. User must make changes if required on their own risk. #> [CmdletBinding()] param() $scriptPath = Join-Path $PSScriptRoot 'Fix-SpeculativeMitigations.ps1' Describe 'Fix-SpeculativeMitigations.ps1' { BeforeAll { . $scriptPath } Context 'Presets and mappings' { It 'has exactly 3 mitigation levels' { if ($Presets.Count -ne 3) { throw "Expected 3 presets, got $($Presets.Count)" } } It 'Level 1 has expected values' { $preset = $Presets.Values | Where-Object { $_.Description -like '*Level 1*' } | Select-Object -First 1 if (-not $preset) { throw "Level 1 preset not found" } if ($preset.OverrideMask -ne 3) { throw "Level 1 OverrideMask mismatch" } if ($preset.Override -ne 0x00800048) { throw "Level 1 Override mismatch: expected 0x00800048, got 0x$($preset.Override.ToString('X8'))" } } It 'Level 2 has expected values' { $preset = $Presets.Values | Where-Object { $_.Description -like '*Level 2*' } | Select-Object -First 1 if (-not $preset) { throw "Level 2 preset not found" } if ($preset.OverrideMask -ne 3) { throw "Level 2 OverrideMask mismatch" } if ($preset.Override -ne 0x00802048) { throw "Level 2 Override mismatch: expected 0x00802048, got 0x$($preset.Override.ToString('X8'))" } } It 'Level 3 has expected values' { $preset = $Presets.Values | Where-Object { $_.Description -like '*Level 3*' } | Select-Object -First 1 if (-not $preset) { throw "Level 3 preset not found" } if ($preset.OverrideMask -ne 3) { throw "Level 3 OverrideMask mismatch" } if ($preset.Override -ne 0x00800000) { throw "Level 3 Override mismatch: expected 0x00800000, got 0x$($preset.Override.ToString('X8'))" } } It 'maps all expected CVEs to bits' { $expectedCves = @( 'CVE-2017-5715','CVE-2017-5754','CVE-2018-3639', 'CVE-2018-3620','CVE-2018-11091','CVE-2018-12126', 'CVE-2018-12127','CVE-2018-12130','CVE-2022-21123', 'CVE-2022-21125','CVE-2022-0001','CVE-2022-23825' ) foreach ($cve in $expectedCves) { if ($CveToBit.Keys -notcontains $cve) { throw "Missing CVE mapping: $cve" } } } It 'does not map OS-only CVEs to registry bits' { $osOnlyCves = @( 'CVE-2022-21127','CVE-2022-21166', 'CVE-2023-20569','CVE-2023-20588', 'CVE-2023-28746','CVE-2022-40982' ) foreach ($cve in $osOnlyCves) { if ($CveToBit.Keys -contains $cve) { throw "Unexpected CVE mapping: $cve" } } } } Context 'Test-Administrator' { It 'returns a boolean' { $result = Test-Administrator if ($result.GetType().Name -ne 'Boolean') { throw "Expected Boolean, got $($result.GetType().Name)" } } } Context 'Get-RegistryValue' { It 'returns null for missing value' { $result = Get-RegistryValue -Name 'SpeculativeMitigation_DoesNotExist_12345' if ($null -ne $result) { throw "Expected null for missing registry value" } } } Context 'Set-RegistryDword' { $script:testName = 'SpecMit_PesterTest' It 'sets and reads back a DWORD' { if (-not ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Warning 'Skipping registry write test - not running as Administrator' return } $set = Set-RegistryDword -Name $script:testName -Value 0x12345678 if (-not $set) { throw "Failed to set registry value" } $read = Get-RegistryValue -Name $script:testName if ($read -ne 0x12345678) { throw "Read back mismatch: expected 0x12345678, got $read" } } AfterEach { if ($script:testName) { Remove-ItemProperty -Path $RegistryPath -Name $script:testName -ErrorAction SilentlyContinue } } } Context 'Test-HyperThreadingEnabled' { It 'returns a boolean' { $result = Test-HyperThreadingEnabled if ($result.GetType().Name -ne 'Boolean') { throw "Expected Boolean, got $($result.GetType().Name)" } } } Context 'Get-InstalledKbNumbers' { It 'returns an array' { $kbs = Get-InstalledKbNumbers if ($kbs.GetType().Name -ne 'Object[]') { throw "Expected array, got $($kbs.GetType().Name)" } } } Context 'Test-KbInstalled' { It 'returns a boolean for any KB string' { $result = Test-KbInstalled -kbNumber 'KB9999999' if ($result.GetType().Name -ne 'Boolean') { throw "Expected Boolean, got $($result.GetType().Name)" } } } Context 'Test-PendingReboot' { It 'returns a boolean' { $result = Test-PendingReboot if ($result.GetType().Name -ne 'Boolean') { throw "Expected Boolean, got $($result.GetType().Name)" } } } Context 'Test-DiskSpace' { It 'returns false when given an absurdly high requirement' { $result = Test-DiskSpace -MbRequired 999999999 if ($result -ne $false) { throw "Expected false for impossible disk space requirement" } } } Context 'Get-CveRecommendation' { It 'returns a non-empty string for known CVE' { $rec = Get-CveRecommendation -CveId 'CVE-2017-5715' if ($rec -notmatch 'Registry') { throw "Expected Registry recommendation, got: $rec" } } It 'returns guidance string for OS-only CVE' { $rec = Get-CveRecommendation -CveId 'CVE-2022-21127' if ($rec -notmatch 'KB') { throw "Expected KB recommendation, got: $rec" } } It 'returns fallback for unknown CVE' { $rec = Get-CveRecommendation -CveId 'CVE-9999-9999' if ($rec -notmatch 'Unknown') { throw "Expected Unknown fallback, got: $rec" } } } Context 'Get-VulnerableCvesFromXml' { It 'returns only vulnerable CVEs from XML' { $xmlPath = Join-Path $env:TEMP 'SpeculativeMitigation_PesterTest.xml' $xmlContent = @' <?xml version="1.0" encoding="utf-8"?> <SpeculativeMitigationReport> <Mitigations> <CVE Name="CVE-2017-5715 (BTI)" Status="Mitigated"> <HardwarePresent>True</HardwarePresent> <WindowsSupportEnabled>True</WindowsSupportEnabled> </CVE> <CVE Name="CVE-2022-21127 (SRBDS Update)" Status="Vulnerable - Update Required"> <RequiredKB>KB5015018</RequiredKB> <MinimumBuild>20348</MinimumBuild> <CurrentBuild>19045</CurrentBuild> </CVE> <CVE Name="CVE-2018-3639 (SSBD)" Status="Not Vulnerable"> <HardwarePresent>False</HardwarePresent> <OSEnabledSystemWide>False</OSEnabledSystemWide> </CVE> </Mitigations> </SpeculativeMitigationReport> '@ Set-Content -Path $xmlPath -Value $xmlContent -Encoding UTF8 try { $vulns = Get-VulnerableCvesFromXml -XmlPath $xmlPath if ($vulns -isnot [array]) { throw "Expected array, got $($vulns.GetType().FullName)" } if ($vulns.Count -ne 1) { throw "Expected 1 vulnerable CVE, got $($vulns.Count)" } if ($vulns[0].CveName -ne 'CVE-2022-21127 (SRBDS Update)') { throw "CVE name mismatch" } if ($vulns[0].RequiredKB -ne 'KB5015018') { throw "RequiredKB mismatch" } } finally { Remove-Item $xmlPath -ErrorAction SilentlyContinue } } It 'returns empty array for missing file' { $vulns = Get-VulnerableCvesFromXml -XmlPath 'Z:\DoesNotExist.xml' if ($vulns -isnot [array]) { throw "Expected array for missing file, got $($vulns.GetType().FullName)" } if ($vulns.Count -ne 0) { throw "Expected 0 results for missing file, got $($vulns.Count)" } } } } |