Set-WindowsSpeculativeMitigation.ps1
|
<# .SYNOPSIS Remediates speculative execution vulnerabilities on Windows by configuring FeatureSettingsOverride and FeatureSettingsOverrideMask registry values. .DESCRIPTION This script sets the Windows registry values FeatureSettingsOverrideMask and FeatureSettingsOverride under: HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management to mitigate speculative execution vulnerabilities including Spectre, Meltdown, L1TF, MDS, TAA, and Intel Branch History Injection (BHI / CVE-2022-0001). Three mitigation levels are available: Level 1 - All speculative execution CVEs including CVE-2022-0001 with Hyper-Threading enabled (Recommended) Level 2 - All speculative execution CVEs including CVE-2022-0001 with Hyper-Threading disabled Level 3 - CVE-2022-0001 (Intel BHI) only - use only if other speculative execution mitigations are managed separately .PARAMETER Level Mitigation level: 1, 2, or 3. Default is 1. .EXAMPLE .\Set-WindowsSpeculativeMitigation.ps1 -Level 1 Applies comprehensive mitigation with Hyper-Threading enabled. .EXAMPLE .\Set-WindowsSpeculativeMitigation.ps1 -Level 2 Applies comprehensive mitigation with Hyper-Threading disabled. .EXAMPLE .\Set-WindowsSpeculativeMitigation.ps1 -Level 3 Applies CVE-2022-0001 (Intel BHI) mitigation only. Use only if other speculative execution mitigations are already managed separately. .NOTES Requires administrator privileges. A system reboot is required for changes to take effect. #> <#PSScriptInfo .VERSION 1.0.0 .GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890 .AUTHOR PowerShell Scripts Collection .COMPANYNAME PowerShell Scripts Collection .COPYRIGHT (c) 2026 PowerShell Scripts Collection .TAGS @('SpeculativeExecution','Spectre','Meltdown','BHI','Security','Windows') .LICENSEURI .PROJECTURI .ICONURI .RELEASENOTES Initial release with CVE-2022-0001 BHI mitigation and Hyper-Threading validation. #> [CmdletBinding()] param( [ValidateSet(1, 2, 3)] [int]$Level = 1 ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' $RegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management' $OverrideMaskName = 'FeatureSettingsOverrideMask' $OverrideName = 'FeatureSettingsOverride' $Settings = @{ 1 = @{ OverrideMask = 3 Override = 0x00800048 Description = 'All speculative execution CVEs including CVE-2022-0001 (Hyper-Threading enabled)' } 2 = @{ OverrideMask = 3 Override = 0x00802048 Description = 'All speculative execution CVEs including CVE-2022-0001 (Hyper-Threading disabled)' } 3 = @{ OverrideMask = 3 Override = 0x00800000 Description = 'CVE-2022-0001 (Intel BHI) only - use only if other speculative execution mitigations are managed separately' } } function Test-Administrator { $identity = [Security.Principal.WindowsIdentity]::GetCurrent() $principal = [Security.Principal.WindowsPrincipal]::new($identity) return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Get-CurrentRegistryValue { param([string]$Name) try { $val = Get-ItemProperty -Path $RegistryPath -Name $Name -ErrorAction SilentlyContinue if ($null -ne $val -and $null -ne $val.$Name) { return [uint32]$val.$Name } } catch { return $null } return $null } function Set-RegistryDword { param( [string]$Name, [uint32]$Value ) try { if (-not (Test-Path $RegistryPath)) { New-Item -Path $RegistryPath -Force | Out-Null } Set-ItemProperty -Path $RegistryPath -Name $Name -Value $Value -Type DWord -Force return $true } catch { Write-Error "Failed to set $Name`: $_" return $false } } function Test-HyperThreadingEnabled { $processors = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue if ($null -eq $processors) { return $false } $totalCores = 0 $totalLogical = 0 foreach ($proc in $processors) { $totalCores += [uint32]$proc.NumberOfCores $totalLogical += [uint32]$proc.NumberOfLogicalProcessors } if ($totalLogical -gt $totalCores) { return $true } return $false } function Main { Write-Host '=== Windows Speculative Execution Mitigation Script ===' -ForegroundColor Cyan Write-Host '' if (-not (Test-Administrator)) { Write-Error 'This script requires administrator privileges. Please run as Administrator.' exit 1 } $htEnabled = Test-HyperThreadingEnabled Write-Host "Hyper-Threading Detected: $(if ($htEnabled) { 'ENABLED' } else { 'DISABLED' })" -ForegroundColor $(if ($htEnabled) { 'Green' } else { 'Yellow' }) Write-Host '' $config = $Settings[$Level] Write-Host "Mitigation Level: $Level - $($config.Description)" -ForegroundColor Yellow Write-Host "Registry Path: $RegistryPath" Write-Host '' if (-not $htEnabled -and $Level -eq 1) { Write-Host 'VALIDATION FAILED: Hyper-Threading is DISABLED on this server.' -ForegroundColor Red Write-Host 'Level 1 requires Hyper-Threading to be enabled.' -ForegroundColor Red Write-Host '' if (-not [Console]::IsInputRedirected) { $continue = Read-Host 'Do you want to continue with Level 2 instead? (Y/N)' if ($continue -ne 'Y' -and $continue -ne 'y') { Write-Host 'Exiting without making changes.' -ForegroundColor Red exit 1 } } else { Write-Host 'Non-interactive session detected. Automatically switching to Level 2.' -ForegroundColor Yellow } $Level = 2 $config = $Settings[$Level] Write-Host "Switching to Level 2 - $($config.Description)" -ForegroundColor Yellow Write-Host '' } if ($htEnabled -and $Level -eq 2) { Write-Host 'WARNING: Hyper-Threading is ENABLED on this server, but Level 2 disables Hyper-Threading mitigations.' -ForegroundColor Yellow Write-Host 'This will affect performance. Press Ctrl+C to cancel, or wait 5 seconds to continue...' -ForegroundColor Yellow Start-Sleep -Seconds 5 } $currentMask = Get-CurrentRegistryValue -Name $OverrideMaskName $currentOverride = Get-CurrentRegistryValue -Name $OverrideName Write-Host '--- Current Settings ---' Write-Host "FeatureSettingsOverrideMask : 0x$($currentMask.ToString('X8')) ($currentMask)" Write-Host "FeatureSettingsOverride : 0x$($currentOverride.ToString('X8')) ($currentOverride)" Write-Host '' $maskNeedsChange = $currentMask -ne $config.OverrideMask $overrideNeedsChange = $currentOverride -ne $config.Override if (-not $maskNeedsChange -and -not $overrideNeedsChange) { Write-Host 'System is already configured with the recommended settings. No changes needed.' -ForegroundColor Green exit 0 } Write-Host '--- Applying Recommended Settings ---' $maskApplied = $true $overrideApplied = $true if ($maskNeedsChange) { Write-Host "Setting $OverrideMaskName to $($config.OverrideMask)..." if (Set-RegistryDword -Name $OverrideMaskName -Value $config.OverrideMask) { Write-Host " $OverrideMaskName set successfully." -ForegroundColor Green } else { $maskApplied = $false } } else { Write-Host "$OverrideMaskName already set to $($config.OverrideMask). Skipping." } if ($overrideNeedsChange) { Write-Host "Setting $OverrideName to 0x$($config.Override.ToString('X8')) ($($config.Override))..." if (Set-RegistryDword -Name $OverrideName -Value $config.Override) { Write-Host " $OverrideName set successfully." -ForegroundColor Green } else { $overrideApplied = $false } } else { Write-Host "$OverrideName already set to $($config.Override). Skipping." } Write-Host '' if ($maskApplied -and $overrideApplied) { Write-Host 'All settings applied successfully.' -ForegroundColor Green Write-Host '' Write-Host 'IMPORTANT: A system reboot is required for these changes to take effect.' -ForegroundColor Red Write-Host 'Reboot command: shutdown /r /t 0' } else { Write-Error 'One or more settings failed to apply. Please review the errors above.' exit 1 } } Main |