Check-SpeculativeMitigations.ps1

<#
.SYNOPSIS
    Comprehensive check of speculative execution mitigations for Windows Server.

.DESCRIPTION
    Queries NtQuerySystemInformation and registry to report mitigation status for:
      CVE-2017-5715 Branch Target Injection (BTI)
      CVE-2017-5753 Bounds Check Bypass (BCB / Spectre Variant 1)
      CVE-2017-5754 Rogue Data Cache Load (RDCL / Meltdown)
      CVE-2018-3639 Speculative Store Bypass (SSBD)
      CVE-2018-3615, CVE-2018-3620, CVE-2018-3646 (L1 Terminal Fault)
      CVE-2018-11091, CVE-2018-12126, CVE-2018-12127, CVE-2018-12130 (MDS)
      CVE-2022-21123 (SBDR)
      CVE-2022-21125 (SBDS)
      CVE-2022-21127 (SRBDS Update)
      CVE-2022-21166 (DRPW)
      CVE-2022-0001 (Intel BHI)
      CVE-2022-23825 (Branch Type Confusion / Retbleed)
      CVE-2023-20569 (Return Address Predictor / SRSO)
      CVE-2022-40982 (GDS)
      CVE-2023-20588 (Divide By Zero)
      CVE-2023-28746 (RFDS)

.EXAMPLE
    .\Check-SpeculativeMitigations.ps1
    Reports mitigation status in human-readable format.

.EXAMPLE
    .\Check-SpeculativeMitigations.ps1 -OutputXml
    Outputs results in both human-readable format and XML.

.EXAMPLE
    .\Check-SpeculativeMitigations.ps1 -OutputXml -OutputPath "C:\Reports\speculation.xml"
    Outputs results in both formats to the specified XML path.

.NOTES
    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.
    Run as Administrator for full results.
    XML output can be consumed by Set-WindowsSpeculativeMitigation.ps1 for targeted remediation.

.PARAMETER OutputXml
    Switch parameter to output results in XML format in addition to human-readable format.

.PARAMETER OutputPath
    Specify the file path for XML output. If not specified, defaults to the TEMP directory.

#>


[CmdletBinding()]
param(
    [switch]$OutputXml,
    [string]$OutputPath
)

Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'

$RegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management'

$NtQSIDefinition = @'
[DllImport("ntdll.dll")]
public static extern int NtQuerySystemInformation(uint systemInformationClass, IntPtr systemInformation, uint systemInformationLength, IntPtr returnLength);
'@


function Test-Administrator {
    $identity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = [Security.Principal.WindowsPrincipal]::new($identity)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Get-RegistryValue {
    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
}

function Get-CpuInfo {
    $cpu = Get-CimInstance Win32_Processor -ErrorAction SilentlyContinue
    if ($cpu -is [array]) { $cpu = $cpu[0] }
    [PSCustomObject]@{
        Manufacturer      = $cpu.Manufacturer
        Name              = $cpu.Name
        NumberOfCores     = $cpu.NumberOfCores
        NumberOfLogicalProcessors = $cpu.NumberOfLogicalProcessors
        Description       = $cpu.Description
    }
}

function Get-OsInfo {
    $os = Get-CimInstance Win32_OperatingSystem -ErrorAction SilentlyContinue
    [PSCustomObject]@{
        Caption     = $os.Caption
        Version     = $os.Version
        BuildNumber = [uint32]$os.BuildNumber
        ProductType = $os.ProductType
    }
}

function Get-MinimumBuilds {
    [ordered]@{
        'Windows Server 2022'    = 20348
        'Windows Server 2019'    = 17763
        'Windows Server 2016'    = 14393
        'Windows 10 21H2'        = 19044
        'Windows 11 21H2'        = 22000
    }
}

function Test-SrbdsDrpwMitigation {
    param([string]$OsCaption, [uint32]$BuildNumber)
    $minimums = Get-MinimumBuilds
    $requiredKbs = @{
        'Windows Server 2022' = 'KB5015018'
        'Windows Server 2019' = 'KB5015017'
        'Windows Server 2016' = 'KB5015019'
        'Windows 10 21H2'     = 'KB5015020'
        'Windows 11 21H2'     = 'KB5015020'
    }
    $captionKey = $minimums.Keys | Where-Object { $OsCaption -like "*$_*" } | Select-Object -First 1
    if (-not $captionKey) {
        $captionKey = $minimums.Keys | Where-Object { $OsCaption -like "*Server*" } | Select-Object -First 1
    }
    if (-not $captionKey) {
        return [PSCustomObject]@{ Status = 'Unknown OS'; RequiredKB = 'N/A'; CurrentBuild = $BuildNumber }
    }
    $minBuild = $minimums[$captionKey]
    $requiredKb = $requiredKbs[$captionKey]
    $mitigated = $BuildNumber -ge $minBuild
    [PSCustomObject]@{
        Status = if ($mitigated) { 'Mitigated' } else { 'Vulnerable - Update Required' }
        RequiredKB = $requiredKb
        MinimumBuild = $minBuild
        CurrentBuild = $BuildNumber
    }
}

function Export-MitigationReportToXml {
    param(
        [PSCustomObject]$Report,
        [string]$OutputPath
    )
    
    $xmlWriter = New-Object System.Xml.XmlTextWriter($OutputPath, $null)
    $xmlWriter.Formatting = 'Indented'
    $xmlWriter.Indentation = 2
    
    $xmlWriter.WriteStartDocument()
    $xmlWriter.WriteStartElement('SpeculativeMitigationReport')
    
    $xmlWriter.WriteStartElement('SystemInfo')
    $xmlWriter.WriteElementString('ComputerName', $Report.ComputerName)
    $xmlWriter.WriteElementString('Date', $Report.Date)
    $xmlWriter.WriteElementString('CPU', $Report.CPU)
    $xmlWriter.WriteElementString('Manufacturer', $Report.Manufacturer)
    $xmlWriter.WriteElementString('OS', $Report.OS)
    $xmlWriter.WriteElementString('OSBuild', $Report.OSBuild.ToString())
    $xmlWriter.WriteElementString('Admin', $Report.Admin.ToString())
    $xmlWriter.WriteEndElement()
    
    $xmlWriter.WriteStartElement('RegistrySettings')
    $xmlWriter.WriteElementString('FeatureSettingsOverrideMask', "0x$($Report.RegistryOverrideMask.ToString('X8'))")
    $xmlWriter.WriteElementString('FeatureSettingsOverride', "0x$($Report.RegistryOverride.ToString('X8'))")
    if ($Report.PSObject.Properties.Name -contains 'SpeculationControlFlags' -and $Report.SpeculationControlFlags) {
        $xmlWriter.WriteElementString('SpeculationControlFlags', "0x$($Report.SpeculationControlFlags.ToString('X8'))")
    }
    $xmlWriter.WriteEndElement()
    
    $xmlWriter.WriteStartElement('Mitigations')
    foreach ($entry in $Report.Mitigations.GetEnumerator()) {
        $cveName = $entry.Key
        $cveData = $entry.Value
        if ($null -eq $cveData) { continue }
        $xmlWriter.WriteStartElement('CVE')
        $xmlWriter.WriteAttributeString('Name', [string]$cveName)
        if ($cveData.PSObject.Properties.Name -contains 'Status') {
            $xmlWriter.WriteAttributeString('Status', [string]$cveData.Status)
        }
        foreach ($prop in $cveData.PSObject.Properties) {
            $propName = $prop.Name
            $propValue = $prop.Value
            if ($null -ne $propValue) {
                $xmlWriter.WriteElementString($propName, [string]$propValue)
            }
        }
        $xmlWriter.WriteEndElement()
    }
    $xmlWriter.WriteEndElement()
    
    $xmlWriter.WriteStartElement('RawData')
    $jsonData = $Report | ConvertTo-Json -Depth 5 -Compress
    $xmlWriter.WriteCData($jsonData)
    $xmlWriter.WriteEndElement()
    
    $xmlWriter.WriteEndElement()
    $xmlWriter.WriteEndDocument()
    $xmlWriter.Flush()
    $xmlWriter.Close()
    
    return [xml](Get-Content $OutputPath -Raw)
}

function Main {
    Write-Host '=== Windows Speculative Execution Mitigation Checker ===' -ForegroundColor Cyan
    Write-Host ''
    Write-Host "Date: $(Get-Date)" -ForegroundColor DarkGray
    Write-Host "Computer: $env:COMPUTERNAME" -ForegroundColor DarkGray
    Write-Host "User: $env:USERNAME" -ForegroundColor DarkGray
    Write-Host "Admin: $(Test-Administrator)" -ForegroundColor DarkGray
    Write-Host ''

    if (-not (Test-Administrator)) {
        Write-Warning 'Not running as Administrator. Some mitigation details may be unavailable.'
        Write-Host ''
    }

    $cpu = Get-CpuInfo
    $os = Get-OsInfo
    Write-Host "CPU: $($cpu.Name)" -ForegroundColor Yellow
    Write-Host "Manufacturer: $($cpu.Manufacturer)" -ForegroundColor Yellow
    Write-Host "Cores / Logical: $($cpu.NumberOfCores) / $($cpu.NumberOfLogicalProcessors)" -ForegroundColor Yellow
    Write-Host "OS: $($os.Caption) Build $($os.BuildNumber)" -ForegroundColor Yellow
    Write-Host ''

    $overrideMask = Get-RegistryValue -Name 'FeatureSettingsOverrideMask'
    $override = Get-RegistryValue -Name 'FeatureSettingsOverride'
    $specCtrlFlags = Get-RegistryValue -Name 'SpeculationControlFlags'

    Write-Host '--- Registry Settings ---' -ForegroundColor Cyan
    Write-Host "FeatureSettingsOverrideMask : 0x$($overrideMask.ToString('X8'))"
    Write-Host "FeatureSettingsOverride : 0x$($override.ToString('X8'))"
    if ($null -ne $specCtrlFlags) {
        Write-Host "SpeculationControlFlags : 0x$($specCtrlFlags.ToString('X8'))"
    } else {
        Write-Host "SpeculationControlFlags : Not present"
    }
    Write-Host ''

    $ntdll = Add-Type -MemberDefinition $NtQSIDefinition -Name 'ntdll' -Namespace 'Win32' -PassThru
    $length = 8
    $ptr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($length)
    $retLen = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4)
    $class201 = 201

    $flags = [uint32]0
    $flags2 = [uint32]0

    try {
        $ret = $ntdll::NtQuerySystemInformation($class201, $ptr, $length, $retLen)
        if ($ret -eq 0) {
            $flags = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($ptr)
            $returnLen = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($retLen)
            if ($returnLen -gt 4) {
                $flags2 = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($ptr, 4)
            }
        }
    }
    catch {
        Write-Warning "Failed to query System Speculation Control Information: $_"
    }

    $manufacturer = $cpu.Manufacturer
    $isIntel = $manufacturer -eq 'GenuineIntel'
    $isAmd = $manufacturer -eq 'AuthenticAMD'

    if ($isIntel -and $cpu.Description -match 'Family (\d+) Model (\d+) Stepping (\d+)') {
        $intelFamily = [uint32]$Matches[1]
        $intelModel = [uint32]$Matches[2]
        $intelStepping = [uint32]$Matches[3]
    }

    $PROCESSOR_ARCHITECTURE_ARM64 = 12
    $PROCESSOR_ARCHITECTURE_ARM   = 5
    $arch = (Get-CimInstance Win32_Processor).Architecture
    $isArm = ($arch -eq $PROCESSOR_ARCHITECTURE_ARM) -or ($arch -eq $PROCESSOR_ARCHITECTURE_ARM64)

    $scfBpbEnabled                        = 0x01
    $scfBpbDisabledSystemPolicy           = 0x02
    $scfBpbDisabledNoHardwareSupport      = 0x04
    $scfSpecCtrlEnumerated                = 0x08
    $scfSpecCmdEnumerated                 = 0x10
    $scfIbrsPresent                       = 0x20
    $scfStibpPresent                      = 0x40
    $scfSmepPresent                       = 0x80
    $scfSsbdAvailable                     = 0x100
    $scfSsbdSupported                     = 0x200
    $scfSsbdSystemWide                    = 0x400
    $scfSsbdRequired                      = 0x1000
    $scfSpecCtrlRetpolineEnabled          = 0x4000
    $scfSpecCtrlImportOptimizationEnabled = 0x8000
    $scfEnhancedIbrs                      = 0x10000
    $scfHvL1tfStatusAvailable             = 0x20000
    $scfHvL1tfProcessorNotAffected        = 0x40000
    $scfHvL1tfMigitationEnabled           = 0x80000
    $scfHvL1tfMigitationNotEnabled_Hardware = 0x100000
    $scfHvL1tfMigitationNotEnabled_LoadOption = 0x200000
    $scfHvL1tfMigitationNotEnabled_CoreScheduler = 0x400000
    $scfEnhancedIbrsReported              = 0x800000
    $scfMdsHardwareProtected              = 0x1000000
    $scfMbClearEnabled                    = 0x2000000
    $scfMbClearReported                   = 0x4000000

    $scf2SbdrSsdpHardwareProtected = 0x01
    $scf2FbsdpHardwareProtected    = 0x02
    $scf2PsdpHardwareProtected     = 0x04
    $scf2FbClearEnabled            = 0x08
    $scf2FbClearReported           = 0x10
    $scf2BhbEnabled                = 0x20
    $scf2BhbDisabledSystemPolicy   = 0x40
    $scf2BhbDisabledNoHardwareSupport = 0x80
    $scf2BranchConfusionStatus     = 0x300
    $scf2BranchConfusionReported   = 0x400
    $scf2RdclHardwareProtectedReported = 0x800
    $scf2RdclHardwareProtected     = 0x1000
    $scf2GdsReported               = 0x2000
    $scf2GdsStatus                 = 0x1C000
    $scf2SrsoReported              = 0x20000
    $scf2SrsoStatus                = 0xC0000
    $scf2DivideByZeroReported      = 0x100000
    $scf2DivideByZeroStatus        = 0x200000
    $scf2RfdsReported              = 0x400000
    $scf2RfdsStatus                = 0x1800000

    $btiHardwarePresent = ((($flags -band $scfSpecCtrlEnumerated) -ne 0) -or (($flags -band $scfSpecCmdEnumerated) -ne 0))
    $btiWindowsSupportPresent = $true
    $btiWindowsSupportEnabled = (($flags -band $scfBpbEnabled) -ne 0)
    $btiDisabledBySystemPolicy = $false
    $btiDisabledByNoHardwareSupport = $false
    $btiRetpolineEnabled = (($flags -band $scfSpecCtrlRetpolineEnabled) -ne 0)
    $btiImportOptimizationEnabled = (($flags -band $scfSpecCtrlImportOptimizationEnabled) -ne 0)

    if ($btiWindowsSupportEnabled -eq $false) {
        $btiDisabledBySystemPolicy = (($flags -band $scfBpbDisabledSystemPolicy) -ne 0)
        $btiDisabledByNoHardwareSupport = (($flags -band $scfBpbDisabledNoHardwareSupport) -ne 0)
    }

    $ssbdAvailable = (($flags -band $scfSsbdAvailable) -ne 0)
    $ssbdHardwarePresent = (($flags -band $scfSsbdSupported) -ne 0)
    $ssbdSystemWide = (($flags -band $scfSsbdSystemWide) -ne 0)
    $ssbdRequired = (($flags -band $scfSsbdRequired) -ne 0)

    $sbdrSsdpHardwareProtected = (($flags2 -band $scf2SbdrSsdpHardwareProtected) -ne 0)
    $fbsdpHardwareProtected = (($flags2 -band $scf2FbsdpHardwareProtected) -ne 0)
    $psdpHardwareProtected = (($flags2 -band $scf2PsdpHardwareProtected) -ne 0)
    $fbClearEnabled = (($flags2 -band $scf2FbClearEnabled) -ne 0)
    $fbClearReported = (($flags2 -band $scf2FbClearReported) -ne 0)

    $rdclHardwareProtectedReported = (($flags2 -band $scf2RdclHardwareProtectedReported) -ne 0)
    $rdclHardwareProtected = (($flags2 -band $scf2RdclHardwareProtected) -ne 0)

    $bhbEnabled = (($flags2 -band $scf2BhbEnabled) -ne 0)
    $bhbDisabledSystemPolicy = (($flags2 -band $scf2BhbDisabledSystemPolicy) -ne 0)
    $bhbDisabledNoHardwareSupport = (($flags2 -band $scf2BhbDisabledNoHardwareSupport) -ne 0)
    $branchConfusionReported = (($flags2 -band $scf2BranchConfusionReported) -ne 0)
    $gdsReported = (($flags2 -band $scf2GdsReported) -ne 0)
    $gdsStatus = (($flags2 -band $scf2GdsStatus) -shr 14)
    $srsoReported = (($flags2 -band $scf2SrsoReported) -ne 0)
    $srsoStatus = (($flags2 -band $scf2SrsoStatus) -shr 18)
    $divideByZeroReported = (($flags2 -band $scf2DivideByZeroReported) -ne 0)
    $divideByZeroStatus = (($flags2 -band $scf2DivideByZeroStatus) -shr 21)
    $rfdsReported = (($flags2 -band $scf2RfdsReported) -ne 0)
    $rfdsStatus = (($flags2 -band $scf2RfdsStatus) -shr 23)

    $mdsMbClearReported = (($flags -band $scfMbClearReported) -ne 0)
    $mdsMbClearEnabled = (($flags -band $scfMbClearEnabled) -ne 0)
    $mdsHardwareProtected = (($flags -band $scfMdsHardwareProtected) -ne 0)

    if (($isAmd) -or ($isArm)) {
        $mdsHardwareProtected = $true
        $sbdrSsdpHardwareProtected = $true
        $fbsdpHardwareProtected = $true
        $psdpHardwareProtected = $true
    }

    $l1tfVulnerableCpus = [tuple]::Create(6, 26, 4), [tuple]::Create(6, 26, 5), [tuple]::Create(6, 30, 4), [tuple]::Create(6, 30, 5),
                            [tuple]::Create(6, 37, 2), [tuple]::Create(6, 37, 5), [tuple]::Create(6, 42, 7), [tuple]::Create(6, 44, 2),
                            [tuple]::Create(6, 45, 6), [tuple]::Create(6, 45, 7), [tuple]::Create(6, 46, 6), [tuple]::Create(6, 47, 2),
                            [tuple]::Create(6, 58, 9), [tuple]::Create(6, 60, 3), [tuple]::Create(6, 61, 4), [tuple]::Create(6, 62, 4),
                            [tuple]::Create(6, 62, 7), [tuple]::Create(6, 63, 2), [tuple]::Create(6, 63, 4), [tuple]::Create(6, 69, 1),
                            [tuple]::Create(6, 70, 1), [tuple]::Create(6, 78, 3), [tuple]::Create(6, 79, 1), [tuple]::Create(7, 69, 1),
                            [tuple]::Create(6, 85, 3), [tuple]::Create(6, 85, 4), [tuple]::Create(6, 86, 2), [tuple]::Create(6, 86, 3),
                            [tuple]::Create(6, 86, 4), [tuple]::Create(6, 86, 5), [tuple]::Create(6, 94, 3), [tuple]::Create(6, 102, 3),
                            [tuple]::Create(6, 142, 9), [tuple]::Create(6, 142, 10), [tuple]::Create(6, 142, 11), [tuple]::Create(6, 158, 9),
                            [tuple]::Create(6, 158, 10), [tuple]::Create(6, 158, 11), [tuple]::Create(6, 158, 12)

    $l1tfRequired = $false
    if ($isIntel) {
        if (($rdclHardwareProtectedReported -eq $true) -and ($rdclHardwareProtected -eq $true)) {
            $l1tfRequired = $false
        }
        elseif (($flags -band $scfHvL1tfStatusAvailable) -and ($flags -band $scfHvL1tfProcessorNotAffected)) {
            $l1tfRequired = $false
        }
        else {
            $fms = [tuple]::Create([int]$intelFamily, [int]$intelModel, [int]$intelStepping)
            if (-not $l1tfVulnerableCpus.Contains($fms)) {
                $l1tfRequired = $false
            } else {
                $l1tfRequired = $true
            }
        }
    }

    $kvaPtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal(4)
    $kvaFlags = [uint32]0
    $kvaShadowPresent = $false
    try {
        $kvaRet = $ntdll::NtQuerySystemInformation(196, $kvaPtr, 4, $retLen)
        if ($kvaRet -eq 0) {
            $kvaFlags = [uint32][System.Runtime.InteropServices.Marshal]::ReadInt32($kvaPtr)
        }
    }
    catch { }
    finally {
        if ($kvaPtr -ne [System.IntPtr]::Zero) {
            [System.Runtime.InteropServices.Marshal]::FreeHGlobal($kvaPtr)
        }
    }

    $kvaShadowEnabledFlag = 0x01
    $kvaShadowUserGlobalFlag = 0x02
    $kvaShadowPcidFlag = 0x04
    $kvaShadowInvpcidFlag = 0x08
    $kvaShadowRequiredFlag = 0x10
    $kvaShadowRequiredAvailableFlag = 0x20
    $l1tfInvalidPteBitMask = 0xfc0
    $l1tfInvalidPteBitShift = 6
    $l1tfFlushSupportedFlag = 0x1000
    $l1tfMitigationPresentFlag = 0x2000

    $kvaShadowEnabled = ($kvaFlags -band $kvaShadowEnabledFlag) -ne 0
    $kvaShadowPcidEnabled = ((($kvaFlags -band $kvaShadowPcidFlag) -ne 0) -and (($kvaFlags -band $kvaShadowInvpcidFlag) -ne 0))
    $kvaShadowPresent = $true
    if (($kvaFlags -band $kvaShadowRequiredAvailableFlag) -ne 0) {
        $kvaShadowRequired = ($kvaFlags -band $kvaShadowRequiredFlag) -ne 0
    } else {
        if ($isAmd) { $kvaShadowRequired = $false }
        elseif ($isIntel -and $intelFamily -eq 0x6 -and $intelModel -in @(0x1c,0x26,0x27,0x36,0x35)) {
            $kvaShadowRequired = $false
        }
        else { $kvaShadowRequired = $true }
    }

    $l1tfInvalidPteBit = [math]::Floor(($kvaFlags -band $l1tfInvalidPteBitMask) * [math]::Pow(2, -$l1tfInvalidPteBitShift))
    $l1tfFlushSupported = ($kvaFlags -band $l1tfFlushSupportedFlag) -ne 0
    $l1tfMitigationEnabled = ($l1tfInvalidPteBit -ne 0) -and $kvaShadowEnabled
    $l1tfMitigationPresent = ($kvaFlags -band $l1tfMitigationPresentFlag) -ne 0 -or $l1tfMitigationEnabled -or $l1tfFlushSupported

    $srbdsCheck = Test-SrbdsDrpwMitigation -OsCaption $os.Caption -BuildNumber $os.BuildNumber
    $drpwCheck = Test-SrbdsDrpwMitigation -OsCaption $os.Caption -BuildNumber $os.BuildNumber

    $branchConfusionStatus = $null
    if ($branchConfusionReported) {
        if ($isAmd) {
            $branchConfusionStatus = (($flags2 -band $scf2BranchConfusionStatus) -shr 8)
        }
        elseif ($isIntel) {
            if ($btiHardwarePresent -eq $false) {
                $branchConfusionStatus = 2
            }
            elseif ($btiWindowsSupportEnabled -eq $true) {
                $branchConfusionStatus = 3
            }
            else {
                $branchConfusionStatus = 1
            }
        }
    }

    $results = [ordered]@{
        'CVE-2017-5715 (BTI)'         = [PSCustomObject]@{
            HardwarePresent       = $btiHardwarePresent
            WindowsSupportEnabled = $btiWindowsSupportEnabled
            RetpolineEnabled      = $btiRetpolineEnabled
            Status = if ($btiHardwarePresent -and $btiWindowsSupportEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2017-5753 (BCB)'         = [PSCustomObject]@{
            HardwarePresent       = 'N/A (Software/Compiler mitigation)'
            WindowsSupportEnabled = 'N/A (Requires /Qspectre or /guard:cf)'
            Status = 'Verify compiler flags and application recompilation'
        }
        'CVE-2017-5754 (RDCL)'        = [PSCustomObject]@{
            HardwareProtected     = if ($rdclHardwareProtectedReported) { $rdclHardwareProtected } else { 'Unknown' }
            KVARequired           = $kvaShadowRequired
            KVAEnabled            = $kvaShadowEnabled
            Status = if ($rdclHardwareProtected) { 'Hardware Immune' } elseif ($kvaShadowRequired -and $kvaShadowEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2018-3639 (SSBD)'        = [PSCustomObject]@{
            HardwarePresent       = $ssbdHardwarePresent
            OSEnabledSystemWide   = $ssbdSystemWide
            Status = if (-not $ssbdRequired) { 'Not Vulnerable' } elseif ($ssbdSystemWide) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2018-3620 / -3646 (L1TF)' = [PSCustomObject]@{
            HardwareVulnerable    = $l1tfRequired
            MitigationPresent     = $l1tfMitigationPresent
            MitigationEnabled     = $l1tfMitigationEnabled
            FlushSupported        = $l1tfFlushSupported
            Status = if (-not $l1tfRequired) { 'Not Vulnerable' } elseif ($l1tfMitigationEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2018-11091/12126/12127/12130 (MDS)' = [PSCustomObject]@{
            HardwareProtected     = $mdsHardwareProtected
            OSEnabled             = $mdsMbClearEnabled
            Status = if ($mdsHardwareProtected) { 'Hardware Immune' } elseif ($mdsMbClearReported -and $mdsMbClearEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2022-21123 (SBDR)'       = [PSCustomObject]@{
            HardwareProtected     = $sbdrSsdpHardwareProtected
            OSEnabled             = $fbClearEnabled
            Status = if ($sbdrSsdpHardwareProtected) { 'Hardware Immune' } elseif ($fbClearReported -and $fbClearEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2022-21125 (SBDS)'       = [PSCustomObject]@{
            HardwareProtected     = $fbsdpHardwareProtected
            OSEnabled             = $fbClearEnabled
            Status = if ($fbsdpHardwareProtected) { 'Hardware Immune' } elseif ($fbClearReported -and $fbClearEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2022-21127 (SRBDS Update)' = [PSCustomObject]@{
            Status             = $srbdsCheck.Status
            RequiredKB        = $srbdsCheck.RequiredKB
            MinimumBuild      = $srbdsCheck.MinimumBuild
            CurrentBuild      = $srbdsCheck.CurrentBuild
        }
        'CVE-2022-21166 (DRPW)'       = [PSCustomObject]@{
            Status             = $drpwCheck.Status
            RequiredKB        = $drpwCheck.RequiredKB
            MinimumBuild      = $drpwCheck.MinimumBuild
            CurrentBuild      = $drpwCheck.CurrentBuild
        }
        'CVE-2022-0001 (BHI)'         = [PSCustomObject]@{
            Enabled               = $bhbEnabled
            Status = if ($bhbEnabled) { 'Mitigated' } else { 'Vulnerable / Not Mitigated' }
        }
        'CVE-2022-23825 (BTC/Retbleed)' = [PSCustomObject]@{
            Reported              = $branchConfusionReported
            StatusValue           = $branchConfusionStatus
            Status = if (-not $branchConfusionReported) {
                'Not Reported by OS'
            } else {
                switch ($branchConfusionStatus) {
                    0 { 'Unsupported' }
                    1 { 'Mitigation Disabled' }
                    2 { 'Hardware Immune' }
                    3 { 'Mitigated' }
                    default { 'Unknown' }
                }
            }
        }
        'CVE-2023-20569 (SRSO)'       = [PSCustomObject]@{
            Reported              = $srsoReported
            StatusValue           = $srsoStatus
            Status = switch ($srsoStatus) {
                0 { 'Unsupported' }
                1 { 'Disabled' }
                2 { 'Hardware Immune' }
                3 { 'Mitigated' }
                default { 'Unknown' }
            }
        }
        'CVE-2022-40982 (GDS)'        = [PSCustomObject]@{
            Reported              = $gdsReported
            StatusValue           = $gdsStatus
            Status = switch ($gdsStatus) {
                0 { 'Unsupported' }
                1 { 'Disabled' }
                2 { 'Hardware Immune' }
                3 { 'Mitigated' }
                4 { 'Mitigated and Locked' }
                default { 'Unknown' }
            }
        }
        'CVE-2023-20588 (DivByZero)'  = [PSCustomObject]@{
            Reported              = $divideByZeroReported
            StatusValue           = $divideByZeroStatus
            Status = switch ($divideByZeroStatus) {
                0 { 'Hardware Immune' }
                1 { 'Mitigated' }
                default { 'Unknown' }
            }
        }
        'CVE-2023-28746 (RFDS)'       = [PSCustomObject]@{
            Reported              = $rfdsReported
            StatusValue           = $rfdsStatus
            Status = switch ($rfdsStatus) {
                0 { 'Unsupported' }
                1 { 'Disabled' }
                2 { 'Hardware Immune' }
                3 { 'Mitigated' }
                default { 'Unknown' }
            }
        }
    }

    $report = [PSCustomObject]@{
        ComputerName        = $env:COMPUTERNAME
        Date                = Get-Date
        CPU                 = $cpu.Name
        Manufacturer        = $manufacturer
        OS                  = $os.Caption
        OSBuild             = $os.BuildNumber
        Admin               = Test-Administrator
        RegistryOverride    = $override
        RegistryOverrideMask= $overrideMask
        Mitigations         = $results
    }

    $divider = '=' * 90
    $thinDivider = '-' * 90

    Write-Host ''
    Write-Host $divider -ForegroundColor Cyan
    Write-Host ' SPECULATIVE EXECUTION MITIGATION ASSESSMENT REPORT' -ForegroundColor White
    Write-Host $divider -ForegroundColor Cyan
    Write-Host ''
    Write-Host " For more information about the output below, please refer to https://support.microsoft.com/help/4074629" -ForegroundColor DarkGray
    Write-Host ''

    Write-Host ' SYSTEM INFORMATION' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray
    $sysInfo = @(
        @('Computer Name', $env:COMPUTERNAME),
        @('Date/Time', (Get-Date -Format 'yyyy-MM-dd HH:mm:ss')),
        @('User', "$env:USERNAME ($(if (Test-Administrator) { 'Administrator' } else { 'Standard User' }))"),
        @('CPU', $cpu.Name),
        @('Manufacturer', $cpu.Manufacturer),
        @('Cores / Logical', "$($cpu.NumberOfCores) / $($cpu.NumberOfLogicalProcessors)"),
        @('OS', "$($os.Caption) Build $($os.BuildNumber)"),
        @('Admin Privileges', $(if (Test-Administrator) { 'Yes' } else { 'No' }))
    )
    foreach ($row in $sysInfo) {
        $label = $row[0].PadRight(20)
        $value = $row[1]
        Write-Host " $label`: $value"
    }
    Write-Host ''

    Write-Host ' REGISTRY CONFIGURATION' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray
    Write-Host " FeatureSettingsOverrideMask : 0x$($overrideMask.ToString('X8'))"
    Write-Host " FeatureSettingsOverride : 0x$($override.ToString('X8'))"
    if ($null -ne $specCtrlFlags) {
        Write-Host " SpeculationControlFlags : 0x$($specCtrlFlags.ToString('X8'))"
    } else {
        Write-Host " SpeculationControlFlags : Not present (legacy OS / missing KB)"
    }
    Write-Host ''

    function Write-CveSection {
        param(
            [string]$Title,
            [string]$Cve,
            [string[]]$Lines
        )
        Write-Host ''
        Write-Host " $Title" -ForegroundColor Cyan
        foreach ($line in $Lines) {
            Write-Host " $line"
        }
    }

    Write-Host ' DETAILED MITIGATION ANALYSIS' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray

    Write-CveSection -Title 'Speculation control settings for CVE-2017-5715 [branch target injection]' -Cve 'CVE-2017-5715' -Lines @(
        "Hardware support for branch target injection mitigation is present: $btiHardwarePresent",
        "Windows OS support for branch target injection mitigation is present: $btiWindowsSupportPresent",
        "Windows OS support for branch target injection mitigation is enabled: $btiWindowsSupportEnabled"
    )

    Write-CveSection -Title 'Speculation control settings for CVE-2017-5754 [rogue data cache load]' -Cve 'CVE-2017-5754' -Lines @(
        "Hardware is vulnerable to rogue data cache load: $($rdclHardwareProtected -ne $true)",
        "Hardware requires kernel VA shadowing: $kvaShadowRequired",
        "Windows OS support for kernel VA shadow is present: $kvaShadowPresent",
        "Windows OS support for kernel VA shadow is enabled: $kvaShadowEnabled"
    )

    Write-CveSection -Title 'Speculation control settings for CVE-2018-3639 [speculative store bypass]' -Cve 'CVE-2018-3639' -Lines @(
        "Hardware is vulnerable to speculative store bypass: $ssbdRequired",
        "Hardware support for speculative store bypass disable is present: $ssbdHardwarePresent",
        "Windows OS support for speculative store bypass disable is present: $ssbdAvailable",
        "Windows OS support for speculative store bypass disable is enabled system-wide: $ssbdSystemWide"
    )

    Write-CveSection -Title 'Speculation control settings for CVE-2018-3620 [L1 terminal fault]' -Cve 'CVE-2018-3620' -Lines @(
        "Hardware is vulnerable to L1 terminal fault: $l1tfRequired",
        "Windows OS support for L1 terminal fault mitigation is present: $l1tfMitigationPresent",
        "Windows OS support for L1 terminal fault mitigation is enabled: $l1tfMitigationEnabled",
        "L1DFlushSupported: $l1tfFlushSupported"
    )

    Write-CveSection -Title 'Speculation control settings for MDS [microarchitectural data sampling]' -Cve 'MDS' -Lines @(
        "Windows OS support for MDS mitigation is present: $mdsMbClearReported",
        "Hardware is vulnerable to MDS: $(($mdsHardwareProtected -ne $true))",
        "Windows OS support for MDS mitigation is enabled: $mdsMbClearEnabled"
    )

    Write-CveSection -Title 'Speculation control settings for SBDR [shared buffers data read]' -Cve 'SBDR' -Lines @(
        "Windows OS support for SBDR mitigation is present: $fbClearReported",
        "Hardware is vulnerable to SBDR: $(($sbdrSsdpHardwareProtected -ne $true))",
        "Windows OS support for SBDR mitigation is enabled: $fbClearEnabled"
    )

    Write-CveSection -Title 'Speculation control settings for FBSDP [fill buffer stale data propagator]' -Cve 'FBSDP' -Lines @(
        "Windows OS support for FBSDP mitigation is present: $fbClearReported",
        "Hardware is vulnerable to FBSDP: $(($fbsdpHardwareProtected -ne $true))",
        "Windows OS support for FBSDP mitigation is enabled: $fbClearEnabled"
    )

    Write-CveSection -Title 'Speculation control settings for PSDP [primary stale data propagator]' -Cve 'PSDP' -Lines @(
        "Windows OS support for PSDP mitigation is present: $fbClearReported",
        "Hardware is vulnerable to PSDP: $(($psdpHardwareProtected -ne $true))",
        "Windows OS support for PSDP mitigation is enabled: $fbClearEnabled"
    )

    $bhbStatus = if ($bhbEnabled) { 'Enabled' } else { 'Disabled' }
    Write-CveSection -Title 'Speculation control settings for BHB CVE-2022-0001, CVE-2022-0002' -Cve 'BHI' -Lines @(
        "BHB Enabled: $bhbEnabled",
        "BHB Disabled by System Policy: $bhbDisabledSystemPolicy",
        "BHB Disabled by No Hardware Support: $bhbDisabledNoHardwareSupport"
    )

    $branchConfusionString = switch ($branchConfusionStatus) {
        0 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_MITIGATION_UNSUPPORTED' }
        1 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_MITIGATION_DISABLED' }
        2 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_HARDWARE_IMMUNE' }
        3 { 'SYSTEM_SPECULATION_CONTROL_BRANCH_CONFUSION_MITIGATED' }
        default { 'UNKNOWN_VALUE' }
    }
    Write-CveSection -Title 'Speculation control settings for BranchConfusion/Retbleed CVE-2022-23825' -Cve 'Retbleed' -Lines @(
        "BranchConfusionReported: $branchConfusionReported",
        "BranchConfusionStatus: $branchConfusionString"
    )

    $gdsString = switch ($gdsStatus) {
        0 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATION_UNSUPPORTED' }
        1 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATION_DISABLED' }
        2 { 'SYSTEM_SPECULATION_CONTROL_GDS_HARDWARE_IMMUNE' }
        3 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATED' }
        4 { 'SYSTEM_SPECULATION_CONTROL_GDS_MITIGATED_AND_LOCKED' }
        default { 'UNKNOWN_VALUE' }
    }
    Write-CveSection -Title 'Speculation control settings for GDS (Gather Data Sample) CVE-2022-40982' -Cve 'GDS' -Lines @(
        "GDS Reported: $gdsReported",
        "GDS Status: $gdsString"
    )

    $srsoString = switch ($srsoStatus) {
        0 { 'SYSTEM_SPECULATION_CONTROL_SRSO_MITIGATION_UNSUPPORTED' }
        1 { 'SYSTEM_SPECULATION_CONTROL_SRSO_MITIGATION_DISABLED' }
        2 { 'SYSTEM_SPECULATION_CONTROL_SRSO_HARDWARE_IMMUNE' }
        3 { 'SYSTEM_SPECULATION_CONTROL_SRSO_MITIGATED' }
        default { 'UNKNOWN_VALUE' }
    }
    Write-CveSection -Title 'Speculation control settings for SRSO (Speculative Return Stack Overflow) CVE-2023-20569' -Cve 'SRSO' -Lines @(
        "SRSO Reported: $srsoReported",
        "SRSO Status: $srsoString"
    )

    $divideByZeroString = switch ($divideByZeroStatus) {
        0 { 'SYSTEM_SPECULATION_CONTROL_DIVIDE_BY_ZERO_HARDWARE_IMMUNE' }
        1 { 'SYSTEM_SPECULATION_CONTROL_DIVIDE_BY_ZERO_MITIGATED' }
        default { 'UNKNOWN_VALUE' }
    }
    Write-CveSection -Title 'Speculation control settings for DivideByZero CVE-2023-20588' -Cve 'DivideByZero' -Lines @(
        "DivideByZero Reported: $divideByZeroReported",
        "DivideByZero Status: $divideByZeroString"
    )

    $rfdsString = switch ($rfdsStatus) {
        0 { 'SYSTEM_SPECULATION_CONTROL_RFDS_MITIGATION_UNSUPPORTED' }
        1 { 'SYSTEM_SPECULATION_CONTROL_RFDS_MITIGATION_DISABLED' }
        2 { 'SYSTEM_SPECULATION_CONTROL_RFDS_HARDWARE_IMMUNE' }
        3 { 'SYSTEM_SPECULATION_CONTROL_RFDS_MITIGATED' }
        default { 'UNKNOWN_VALUE' }
    }
    Write-CveSection -Title 'Speculation control settings for RFDS (Register File Data Sampling) CVE-2023-28746' -Cve 'RFDS' -Lines @(
        "RFDS Reported: $rfdsReported",
        "RFDS Status: $rfdsString"
    )

    Write-Host ''
    Write-Host $thinDivider -ForegroundColor DarkGray
    Write-Host ' COMPLIANCE SCORECARD' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray

    $mitigationData = @()
    foreach ($cve in $results.Keys) {
        $r = $results[$cve]
        $status = $r.Status
        $indicator = switch -regex ($status) {
            'Mitigated|Hardware Immune|Not Vulnerable' { '[PASS]' }
            'Vulnerable|Disabled|Unsupported' { '[FAIL]' }
            default { '[INFO]' }
        }
        $mitigationData += [PSCustomObject]@{
            CVE = $cve
            Status = $status
            Indicator = $indicator
        }
    }

    $passCount = ($mitigationData | Where-Object { $_.Status -match 'Mitigated|Hardware Immune|Not Vulnerable' }).Count
    $totalCount = $mitigationData.Count
    $passPercent = [math]::Round(($passCount / $totalCount) * 100)

    foreach ($item in $mitigationData) {
        $color = switch -regex ($item.Status) {
            'Mitigated|Hardware Immune|Not Vulnerable' { 'Green' }
            'Vulnerable|Disabled|Unsupported' { 'Red' }
            default { 'Yellow' }
        }
        Write-Host " $($item.Indicator) $($item.CVE.PadRight(40)) $($item.Status)" -ForegroundColor $color
    }

    Write-Host ''
    Write-Host " SUMMARY: $passCount / $totalCount checks passed ($passPercent%)" -ForegroundColor $(if ($passPercent -eq 100) { 'Green' } elseif ($passPercent -ge 80) { 'Yellow' } else { 'Red' })
    Write-Host ''

    Write-Host ' REMEDIATION RECOMMENDATIONS' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray
    $actions = @()
    if (-not $btiHardwarePresent) { $actions += '[BIOS] Update CPU microcode / firmware for BTI hardware support.' }
    if (-not $btiWindowsSupportEnabled) { $actions += '[Registry] Enable BTI via FeatureSettingsOverride or Windows Update.' }
    if ($kvaShadowRequired -and -not $kvaShadowEnabled) { $actions += '[Registry] Enable Kernel VA Shadow for RDCL/L1TF mitigation.' }
    if ($l1tfRequired -and -not $l1tfMitigationEnabled) { $actions += '[Performance] Enable L1TF mitigation or disable Hyper-Threading.' }
    if ($ssbdRequired -and -not $ssbdSystemWide) { $actions += '[Registry] Enable SSBD system-wide via registry.' }
    if ($mdsMbClearReported -and -not $mdsHardwareProtected -and -not $mdsMbClearEnabled) { $actions += '[Registry] Enable MDS mitigation (MB clear).' }
    if ($fbClearReported -and -not $sbdrSsdpHardwareProtected -and -not $fbClearEnabled) { $actions += '[Registry] Enable FB clear for SBDR/SBDS/PSDP.' }
    if ($srbdsCheck.Status -eq 'Vulnerable - Update Required') { $actions += "[Windows Update] Install $($srbdsCheck.RequiredKB) or later for SRBDS mitigation." }
    if ($drpwCheck.Status -eq 'Vulnerable - Update Required') { $actions += "[Windows Update] Install $($drpwCheck.RequiredKB) or later for DRPW mitigation." }
    if ($actions.Count -eq 0) {
        Write-Host ' All checks passed. No immediate action required.' -ForegroundColor Green
    } else {
        $i = 1
        foreach ($action in $actions) {
            Write-Host " $i. $action"
            $i++
        }
    }
    Write-Host ''

    Write-Host ' RAW DATA OUTPUT' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray
    Write-Host ($report | ConvertTo-Json -Depth 5)
    Write-Host ''

    Write-Host ' OBJECT PROPERTIES' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray
    $hvL1tfStatusAvailableVal = ($flags -band $scfHvL1tfStatusAvailable) -ne 0
    $hvL1tfProcessorNotAffectedVal = ($flags -band $scfHvL1tfProcessorNotAffected) -ne 0
    $mdsHardwareVulnerableVal = $mdsHardwareProtected -ne $true
    $sbdrSsdpHardwareVulnerableVal = $sbdrSsdpHardwareProtected -ne $true
    $fbsdpHardwareVulnerableVal = $fbsdpHardwareProtected -ne $true
    $psdpHardwareVulnerableVal = $psdpHardwareProtected -ne $true

    $props = @(
        @('BTIHardwarePresent', $btiHardwarePresent),
        @('BTIWindowsSupportPresent', $btiWindowsSupportPresent),
        @('BTIWindowsSupportEnabled', $btiWindowsSupportEnabled),
        @('BTIDisabledBySystemPolicy', $btiDisabledBySystemPolicy),
        @('BTIDisabledByNoHardwareSupport', $btiDisabledByNoHardwareSupport),
        @('BTIKernelRetpolineEnabled', $btiRetpolineEnabled),
        @('BTIKernelImportOptimizationEnabled', $btiImportOptimizationEnabled),
        @('RdclHardwareProtectedReported', $rdclHardwareProtectedReported),
        @('RdclHardwareProtected', $rdclHardwareProtected),
        @('KVAShadowRequired', $kvaShadowRequired),
        @('KVAShadowWindowsSupportPresent', $kvaShadowPresent),
        @('KVAShadowWindowsSupportEnabled', $kvaShadowEnabled),
        @('KVAShadowPcidEnabled', $kvaShadowPcidEnabled),
        @('SSBDWindowsSupportPresent', $ssbdAvailable),
        @('SSBDHardwareVulnerable', $ssbdRequired),
        @('SSBDHardwarePresent', $ssbdHardwarePresent),
        @('SSBDWindowsSupportEnabledSystemWide', $ssbdSystemWide),
        @('L1TFHardwareVulnerable', $l1tfRequired),
        @('L1TFWindowsSupportPresent', $l1tfMitigationPresent),
        @('L1TFWindowsSupportEnabled', $l1tfMitigationEnabled),
        @('L1TFInvalidPteBit', $l1tfInvalidPteBit),
        @('L1DFlushSupported', $l1tfFlushSupported),
        @('HvL1tfStatusAvailable', $hvL1tfStatusAvailableVal),
        @('HvL1tfProcessorNotAffected', $hvL1tfProcessorNotAffectedVal),
        @('MDSWindowsSupportPresent', $mdsMbClearReported),
        @('MDSHardwareVulnerable', $mdsHardwareVulnerableVal),
        @('MDSWindowsSupportEnabled', $mdsMbClearEnabled),
        @('FBClearWindowsSupportPresent', $fbClearReported),
        @('SBDRSSDPHardwareVulnerable', $sbdrSsdpHardwareVulnerableVal),
        @('FBSDPHardwareVulnerable', $fbsdpHardwareVulnerableVal),
        @('PSDPHardwareVulnerable', $psdpHardwareVulnerableVal),
        @('FBClearWindowsSupportEnabled', $fbClearEnabled),
        @('BhbEnabled', $bhbEnabled),
        @('BhbDisabledSystemPolicy', $bhbDisabledSystemPolicy),
        @('BhbDisabledNoHardwareSupport', $bhbDisabledNoHardwareSupport),
        @('BranchConfusionReported', $branchConfusionReported),
        @('BranchConfusionStatus', $branchConfusionString),
        @('GdsReported', $gdsReported),
        @('GdsStatus', $gdsString),
        @('SrsoReported', $srsoReported),
        @('SrsoStatus', $srsoString),
        @('DivideByZeroReported', $divideByZeroReported),
        @('DivideByZeroStatus', $divideByZeroString),
        @('RfdsReported', $rfdsReported),
        @('RfdsStatus', $rfdsString)
    )
    foreach ($p in $props) {
        try {
            $name = $p[0].PadRight(40)
            $val = $p[1]
            Write-Host " $name`: $val"
        }
        catch {
            Write-Host " ERROR processing prop: $_"
        }
    }
    Write-Host ''

    $msActions = @()
    if (($btiWindowsSupportPresent -eq $false) -or
        ($kvaShadowPresent -eq $false) -or
        ($ssbdAvailable -eq $false) -or
        ($l1tfMitigationPresent -eq $false) -or
        ($mdsMbClearReported -eq $false) -or
        ($fbClearReported -eq $false) -or
        ($rdclHardwareProtectedReported -eq $false)) {
        $msActions += 'Install the latest available updates for Windows with support for speculation control mitigations.'
    }
    if (($btiWindowsSupportPresent -eq $true -and $btiWindowsSupportEnabled -eq $false) -or
        ($kvaShadowRequired -eq $true -and $kvaShadowEnabled -eq $false) -or
        ($l1tfRequired -eq $true -and $l1tfMitigationEnabled -eq $false) -or
        ($mdsMbClearReported -eq $true -and $mdsHardwareProtected -eq $false -and $mdsMbClearEnabled -eq $false) -or
        ($fbClearReported -eq $true -and $sbdrSsdpHardwareProtected -eq $false -and $fbClearEnabled -eq $false) -or
        ($fbClearReported -eq $true -and $fbsdpHardwareProtected -eq $false -and $fbClearEnabled -eq $false) -or
        ($fbClearReported -eq $true -and $psdpHardwareProtected -eq $false -and $fbClearEnabled -eq $false)) {
        $guidanceUri = ""
        if ($os.ProductType -eq 1) {
            $guidanceUri = "https://support.microsoft.com/help/4073119"
        } else {
            $guidanceUri = "https://support.microsoft.com/help/4072698"
        }
        $msActions += "Follow the guidance for enabling Windows support for speculation control mitigations described in $guidanceUri"
    }

    if ($msActions.Count -gt 0) {
        Write-Host ' SUGGESTED ACTIONS' -ForegroundColor Yellow
        Write-Host $thinDivider -ForegroundColor DarkGray
        foreach ($action in $msActions) {
            Write-Host " * $action"
        }
        Write-Host ''
    }

    Write-Host ' REFERENCES' -ForegroundColor Yellow
    Write-Host $thinDivider -ForegroundColor DarkGray
    Write-Host ' Microsoft Guidance : https://support.microsoft.com/help/4074629'
    Write-Host ' Windows Speculative Execution Mitigations: https://portal.msrc.microsoft.com/en-us/security-guidance/advisory/ADV180002'
    Write-Host ''

    Write-Host $divider -ForegroundColor Cyan
    Write-Host ' END OF REPORT' -ForegroundColor White
    Write-Host $divider -ForegroundColor Cyan
    Write-Host ''

    if ($OutputXml) {
        if (-not $OutputPath) {
            $timestamp = Get-Date -Format 'yyyyMMdd_HHmmss'
            $OutputPath = Join-Path $env:TEMP "SpeculativeMitigation_$env:COMPUTERNAME`_$timestamp.xml"
        }
        Write-Host 'Exporting XML report...' -ForegroundColor Cyan
        try {
            $xmlReport = Export-MitigationReportToXml -Report $report -OutputPath $OutputPath
            Write-Host "XML report saved to: $OutputPath" -ForegroundColor Green
        }
        catch {
            Write-Warning "Failed to export XML report: $_"
        }
    }

    if ($ptr -ne [System.IntPtr]::Zero) {
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr)
    }
    if ($retLen -ne [System.IntPtr]::Zero) {
        [System.Runtime.InteropServices.Marshal]::FreeHGlobal($retLen)
    }
}

Main