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