Recently we had to make some fixes to registry settings because of the Spectre/Meltdown patches for Windows. By default not all registry settings would be properly set, so that patches might not be activated.

In order to fix this, I wrote a little script to easily set the registry keys.

We created an EXE-file from this script using PS2EXE-GUI and are now able to roll it out with our patching software and letting it report back the status using the exit code.

Here’s an altered version of the script (originally we defined variables for each key, name and value and wrote an if-statement for each key/name/value-set):

$_regSettings = @(
    # Reference: https://support.microsoft.com/en-us/help/4072699/january-3-2018-windows-security-updates-and-antivirus-software
    [pscustomobject]@{ Key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\QualityCompat'; Name = 'cadca5fe-87d3-4b96-b7fb-a231484277cc'; Value = '0'; Type = 'DWORD'; FlagValue = 1 }
    # Reference: https://support.microsoft.com/en-hk/help/4073119/protect-against-speculative-execution-side-channel-vulnerabilities-in
    ,[pscustomobject]@{ Key = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management'; Name = 'FeatureSettingsOverride'; Value = '0'; Type = 'DWORD'; FlagValue = 2 }
    ,[pscustomobject]@{ Key = 'HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management'; Name = 'FeatureSettingsOverrideMask'; Value = '3'; Type = 'DWORD'; FlagValue = 4 }
    # Reference: https://support.microsoft.com/en-us/help/4072698/windows-server-guidance-to-protect-against-the-speculative-execution
    # Only for Hyper-V Hosts
    #,[pscustomobject]@{ Key = 'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization'; Name = 'MinVmVersionForCpuBasedMitigations'; Value = '1.0'; Type = 'REG_SZ'; FlagValue = 8 }
)

$_exitCode = 0

foreach ($_regSetting in $_regSettings) {
    switch ($_regSetting.Type) {
        # String. Specifies a null-terminated string. Equivalent to REG_SZ.
        "String"        { $_valueType = "String"; break; }
        "REG_SZ"        { $_valueType = "String"; break; }
        # ExpandString. Specifies a null-terminated string that contains unexpanded references to environment variables that are expanded when the value is retrieved. Equivalent to REG_EXPAND_SZ.
        "ExpandString"  { $_valueType = "String" }
        "REG_EXPAND_SZ" { $_valueType = "String" }
        # Binary. Specifies binary data in any form. Equivalent to REG_BINARY.
        "Binary"        { $_valueType = "Byte[]"; break; }
        "REG_BINARY"    { $_valueType = "Byte[]"; break; }
        # DWord. Specifies a 32-bit binary number. Equivalent to REG_DWORD.
        "DWORD"         { $_valueType = "Int32"; break; }
        "REG_DWORD"     { $_valueType = "Int32"; break; }
        # MultiString. Specifies an array of null-terminated strings terminated by two null characters. Equivalent to REG_MULTI_SZ.
        "MultiString"   { $_valueType = "String[]"; break; }
        "REG_MULTI_SZ"  { $_valueType = "String[]"; break; }
        # Qword. Specifies a 64-bit binary number. Equivalent to REG_QWORD.
        "QWORD"         { $_valueType = "Int64"; break; }
        "REG_QWORD"     { $_valueType = "Int64"; break; }
        # Unknown. Indicates an unsupported registry data type, such as REG_RESOURCE_LIST
        default         {throw "Unknown type" }
    }

    if ((Get-ItemProperty -Path $_regSetting.Key -Name $_regSetting.Name).($_regSetting.Name) -ne $_regSetting.Value -or
        (Get-ItemProperty -Path $_regSetting.Key -Name $_regSetting.Name).($_regSetting.Name).GetType().Name -ne $_valueType) {
        try {
            Write-Verbose -Verbose "Registrysetting not found or not properly set: '$($_regSetting.Key)\$($_regSetting.Name)'"
            if (!(Test-Path $_regSetting.Key)) {
                New-Item -Path $_regSetting.Key
            }
            New-ItemProperty -Path $_regSetting.Key -Name $_regSetting.Name -Value $_regSetting.Value -Force -PropertyType DWORD -ErrorAction Stop
        }
        catch {
            Write-Error "Unable to set registry: '$($_regSetting.Key)\$($_regSetting.Name)'"
            $_exitCode = $_exitCode + $_regSetting.FlagValue
        }
    }
}

<#
$_exitCode 0  : No missing or misconfigured registry keys
$_exitCode 1  : Unable to set QualityCompat
$_exitCode 2  : Unable to set FeatureSettingsOverride
$_exitCode 3  : Unable to set QualityCompat and FeatureSettingsOverride
$_exitCode 4  : Unable to set FeatureSettingsOverrideMask
$_exitCode 5  : Unable to set QualityCompat and FeatureSettingsOverrideMask
$_exitCode 6  : Unable to set FeatureSettingsOverride and FeatureSettingsOverrideMask
$_exitCode 7  : Unable to set QualityCompat, FeatureSettingsOverride and FeatureSettingsOverrideMask
$_exitCode 8  : Unable to set MinVmVersionForCpuBasedMitigations
$_exitCode 9  : Unable to set QualityCompat and MinVmVersionForCpuBasedMitigations
$_exitCode 10 : Unable to set FeatureSettingsOverride and MinVmVersionForCpuBasedMitigations
$_exitCode 11 : Unable to set QualityCompat, FeatureSettingsOverride and MinVmVersionForCpuBasedMitigations
$_exitCode 12 : Unable to set FeatureSettingsOverrideMask and MinVmVersionForCpuBasedMitigations
$_exitCode 13 : Unable to set QualityCompat, FeatureSettingsOverrideMask and MinVmVersionForCpuBasedMitigations
$_exitCode 14 : Unable to set FeatureSettingsOverride, FeatureSettingsOverrideMask and MinVmVersionForCpuBasedMitigations
$_exitCode 15 : Unable to set QualityCompat, FeatureSettingsOverride, FeatureSettingsOverrideMask and MinVmVersionForCpuBasedMitigations
#>
Write-Verbose -Verbose "Exit-code : $_exitCode"
exit($_exitCode)