[REQ-DC-159] Disable Windows Script Host and Remap Scripting Extensions on Domain Controllers
Target Scope
- Applicable Systems: Domain Controllers and Member Servers (Tier 0 Identity Infrastructure). (For Tier 0 Privileged Access Workstations, refer to REQ-PAW-034; for Tier 2 Client Workstations, refer to REQ-END-034).
- Operating Systems: Windows Server 2016, Windows Server 2019, Windows Server 2022, Windows Server 2025.
Implementation Details
- Priority: High
- GPO Paths / Registry Locations:
- GPO Path (WSH Disable): Computer Configuration\Preferences\Windows Settings\Registry
- GPO Path (User Hive): User Configuration\Preferences\Windows Settings\Registry
- GPO Path (Associations): User Configuration\Preferences\Control Panel Settings\Folder Options
- Registry Locations:
HKLM\SOFTWARE\Microsoft\Windows Script Host\SettingsEnabled=0(REG_DWORD)TrustPolicy=2(REG_DWORD)
HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows Script Host\SettingsEnabled=0(REG_DWORD)TrustPolicy=2(REG_DWORD)
HKCU\SOFTWARE\Microsoft\Windows Script Host\SettingsEnabled=0(REG_DWORD)TrustPolicy=2(REG_DWORD)
HKLM\SOFTWARE\Classes\.<ext>(where<ext>=vbs,vbe,js,jse,wsf,wsh,hta)(Default)=txtfile(REG_SZ)
Rationale
Domain Controllers host the Active Directory directory database (NTDS.dit), Kerberos ticket-granting service keys (krbtgt), and credentials for all domain identities. Protecting these Tier 0 identity stores requires aggressive operating system minimization and the systematic neutralization of Living-off-the-Land Binaries (LOLBins / LOLBAS) that adversaries leverage during post-exploitation, lateral movement, and defense evasion:
- Mitigation of LOLBin Abuse on Critical Servers: Windows Script Host binaries (
cscript.exeandwscript.exe) execute legacy VBScript (vbscript.dll) and JScript (jscript.dll) engines. Threat actors targeting Domain Controllers frequently invokecscript.exeormshta.exeto execute obfuscated staging scripts, query Active Directory via legacy ADSI/WMI interfaces, or execute memory injection routines while attempting to evade standard binary application allowlisting (MITRE ATT&CK T1059.005, T1059.007, T1218). - Elimination of Untrusted Script Execution: Disabling WSH system-wide via the
Enabled = 0registry setting prevents the execution of all.vbs,.vbe,.js,.jse,.wsf, and.wshfiles through the primary scripting host, returning an immediate administrative blocking error. - Comprehensive 64-Bit and 32-Bit WOW6432Node Coverage: In 64-bit Windows Server environments, threat actors often invoke 32-bit binaries (
%SystemRoot%\SysWOW64\cscript.exeorwscript.exe) to evade 64-bit security monitoring tools and API hooks. ConfiguringEnabled = 0andTrustPolicy = 2across both the native 64-bit registry branch (HKLM\SOFTWARE\Microsoft\Windows Script Host\Settings) and the 32-bit subsystem branch (HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows Script Host\Settings) closes this evasion vector. - TrustPolicy Hardening: Setting
TrustPolicy = 2enforces restrictions that disallow untrusted scripts system-wide, establishing defense-in-depth even if individual registry keys are tampered with. - Accidental Double-Click Prevention: Remapping legacy scripting extensions (
.vbs,.vbe,.js,.jse,.wsf,.wsh,.hta) totxtfile(notepad.exe) ensures that if an administrator inspects an administrative script or diagnostic file on the DC console, opening the file in Windows Explorer displays plain text in Notepad rather than silently triggering code execution.
Legacy Impact & Compatibility
- Software Licensing Management Tool (
slmgr.vbs):- The Windows Software Licensing Management Tool (
slmgr.vbs) is implemented as a VBScript script executed bycscript.exe. Disabling Windows Script Host prevents direct execution ofslmgr.vbsfrom the command line (e.g.,slmgr.vbs /dliorslmgr.vbs /atowill display an error stating that WSH is disabled). - Enterprise Recommended Solution - Active Directory-Based Activation (ADBA): In enterprise Active Directory environments, Domain Controllers and domain-joined Windows Server instances should utilize Active Directory-Based Activation (ADBA). With ADBA, activation objects are stored directly within the Active Directory forest configuration partition (
CN=Activation Objects,CN=Microsoft Technologies,CN=Services,CN=Configuration,DC=...). Domain Controllers automatically activate upon promotion and domain membership verification without requiring localslmgr.vbsexecution. - Key Management Service (KMS): Environments utilizing centralized KMS host activation handle periodic volume license renewals through the background Software Protection Service (
sppsvc.exe), requiring no manualslmgr.vbsinteraction. - Native PowerShell CIM License Verification: Administrators can query licensing and activation status natively in PowerShell without relying on
slmgr.vbsby inspecting theSoftwareLicensingProductCIM class:Get-CimInstance -ClassName SoftwareLicensingProduct -Filter "PartialProductKey IS NOT NULL" | Select-Object Name, ApplicationId, LicenseStatus, Description. - Manual Staging Workflow (One-Off MAK Activation): If a standalone or non-ADBA Domain Controller requires manual Multiple Activation Key (MAK) entry during initial bare-metal staging, administrators can temporarily enable WSH (
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings" -Name "Enabled" -Value 1), performcscript.exe C:\Windows\System32\slmgr.vbs /ipk <ProductKey>andslmgr.vbs /ato, and immediately re-lock WSH by restoringEnabled = 0.
- The Windows Software Licensing Management Tool (
- Active Directory Core Services:
- Core Active Directory Domain Services (NTDS), Kerberos Key Distribution Center (KDC), DNS Server service, LDAP/LDAPS services, DFS Replication (DFSR), and Group Policy processing (
gpsvc.dll) are compiled native C/C++ services and binaries that have zero dependency on Windows Script Host. Disabling WSH has no impact on directory replication, authentication, or group policy propagation.
- Core Active Directory Domain Services (NTDS), Kerberos Key Distribution Center (KDC), DNS Server service, LDAP/LDAPS services, DFS Replication (DFSR), and Group Policy processing (
- SYSVOL Logon Scripts:
- Legacy logon scripts placed in the
SYSVOLnetlogonshare written in VBScript execute on client workstations (endpoints), not on the Domain Controller itself. However, organizations should systematically modernize legacy.vbslogon scripts to PowerShell 5.1+ or native Group Policy Preferences (GPP) to ensure compatibility with hardened endpoint and PAW baselines.
- Legacy logon scripts placed in the
Implementation Steps
Option A: Group Policy Object (GPO) Configuration (Preferred)
Step 1: Disable WSH via GPO Computer Preferences
- Open the Group Policy Management Console (
gpmc.msc). - Edit the Domain Controller GPO (e.g.,
GPO_Hardening_DomainControllers). - Navigate to:
Computer Configuration\Preferences\Windows Settings\Registry - Create a new Registry Item for the native 64-bit hive:
- Action:
Update - Hive:
HKEY_LOCAL_MACHINE - Key Path:
SOFTWARE\Microsoft\Windows Script Host\Settings - Value Name:
Enabled - Value Type:
REG_DWORD - Value Data:
0
- Action:
- Create a second Registry Item for
TrustPolicy:- Action:
Update - Hive:
HKEY_LOCAL_MACHINE - Key Path:
SOFTWARE\Microsoft\Windows Script Host\Settings - Value Name:
TrustPolicy - Value Type:
REG_DWORD - Value Data:
2
- Action:
- Create a third Registry Item for 32-bit WOW64 disablement:
- Action:
Update - Hive:
HKEY_LOCAL_MACHINE - Key Path:
SOFTWARE\WOW6432Node\Microsoft\Windows Script Host\Settings - Value Name:
Enabled - Value Type:
REG_DWORD - Value Data:
0
- Action:
- Create a fourth Registry Item for 32-bit WOW64 TrustPolicy:
- Action:
Update - Hive:
HKEY_LOCAL_MACHINE - Key Path:
SOFTWARE\WOW6432Node\Microsoft\Windows Script Host\Settings - Value Name:
TrustPolicy - Value Type:
REG_DWORD - Value Data:
2
- Action:
Step 2: Disable WSH in User Configuration Preferences
- Navigate to:
User Configuration\Preferences\Windows Settings\Registry - Create a new Registry Item:
- Action:
Update - Hive:
HKEY_CURRENT_USER - Key Path:
SOFTWARE\Microsoft\Windows Script Host\Settings - Value Name:
Enabled - Value Type:
REG_DWORD - Value Data:
0
- Action:
- Create a second Registry Item:
- Action:
Update - Hive:
HKEY_CURRENT_USER - Key Path:
SOFTWARE\Microsoft\Windows Script Host\Settings - Value Name:
TrustPolicy - Value Type:
REG_DWORD - Value Data:
2
- Action:
Step 3: Remap Script File Extensions to Notepad
- Navigate to:
User Configuration\Preferences\Control Panel Settings\Folder Options - Right-click and select New -> Open With:
- File Extension:
vbs - Associated Program:
%SystemRoot%\System32\notepad.exe - Set as default: Check
- File Extension:
- Repeat for
vbe,js,jse,wsf,wsh, andhta. - Alternatively, configure system-wide registry preferences under
HKLM\SOFTWARE\Classes\.<ext>setting the default string value totxtfile.
Option B: PowerShell & Registry Configuration (Remediation / Non-GPO)
Configure the local registry settings to disable WSH and remap associations.
Download Script: Disable-DcWsh.ps1
# Disable-DcWsh.ps1
# Description: Disables Windows Script Host globally across 64-bit and 32-bit registry hives, enforces TrustPolicy, and remaps script file associations to Notepad on Domain Controllers.
Write-Host "Applying Windows Script Host and file association hardening for Domain Controllers..." -ForegroundColor Cyan
# 1. Disable WSH globally in 64-bit HKLM
$RegistryHklm = "HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings"
if (-not (Test-Path $RegistryHklm)) {
New-Item -Path $RegistryHklm -Force | Out-Null
}
Set-ItemProperty -Path $RegistryHklm -Name "Enabled" -Value 0 -Type DWord -Force
Set-ItemProperty -Path $RegistryHklm -Name "TrustPolicy" -Value 2 -Type DWord -Force
Write-Host "[+] WSH globally disabled and TrustPolicy enforced in HKLM." -ForegroundColor Green
# 2. Disable WSH in WOW6432Node on 64-bit systems
if ([Environment]::Is64BitOperatingSystem) {
$RegistryWow64 = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Script Host\Settings"
if (-not (Test-Path $RegistryWow64)) {
New-Item -Path $RegistryWow64 -Force | Out-Null
}
Set-ItemProperty -Path $RegistryWow64 -Name "Enabled" -Value 0 -Type DWord -Force
Set-ItemProperty -Path $RegistryWow64 -Name "TrustPolicy" -Value 2 -Type DWord -Force
Write-Host "[+] WSH globally disabled and TrustPolicy enforced in HKLM WOW6432Node." -ForegroundColor Green
}
# 3. Disable WSH in current user HKCU hive
$RegistryHkcu = "HKCU:\SOFTWARE\Microsoft\Windows Script Host\Settings"
if (-not (Test-Path $RegistryHkcu)) {
New-Item -Path $RegistryHkcu -Force | Out-Null
}
Set-ItemProperty -Path $RegistryHkcu -Name "Enabled" -Value 0 -Type DWord -Force
Set-ItemProperty -Path $RegistryHkcu -Name "TrustPolicy" -Value 2 -Type DWord -Force
Write-Host "[+] WSH disabled in current user HKCU hive." -ForegroundColor Green
# 4. Remap script file extensions to notepad
$Extensions = @("vbs", "vbe", "js", "jse", "wsf", "wsh", "hta")
foreach ($Ext in $Extensions) {
$ProgIdPath = "HKLM:\SOFTWARE\Classes\.$Ext"
# Update Class Association to Notepad
if (-not (Test-Path $ProgIdPath)) {
New-Item -Path $ProgIdPath -Force | Out-Null
}
Set-ItemProperty -Path $ProgIdPath -Name "" -Value "txtfile" -Type String -Force
Write-Host " Mapped .$Ext extension to txtfile handler." -ForegroundColor Gray
}
Write-Host "[+] Script file extension handlers mapped to Notepad." -ForegroundColor Green
Write-Host "[i] Note: Software Licensing Management Tool (slmgr.vbs) requires ADBA or KMS. Use Get-CimInstance SoftwareLicensingProduct for querying status." -ForegroundColor Yellow
To verify the WSH configuration state:
Download Script: Get-DcWshStatus.ps1
# Get-DcWshStatus.ps1
# Description: Audits Windows Script Host registry state across 64-bit and 32-bit hives and script file extension association handlers on Domain Controllers.
Write-Host "--- Auditing Windows Script Host Hardening on Domain Controllers ---" -ForegroundColor Cyan
$script:Vulnerable = $false
# 1. Audit WSH Registry settings in 64-bit HKLM
$RegistryHklm = "HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings"
if (Test-Path $RegistryHklm) {
$ValHklm = (Get-ItemProperty -Path $RegistryHklm -Name "Enabled" -ErrorAction SilentlyContinue).Enabled
if ($ValHklm -eq 0) {
Write-Host " - HKLM WSH Enabled: 0 (Secure)" -ForegroundColor Green
} else {
Write-Host " - VULNERABLE: HKLM WSH is enabled or not configured (Value: '$($ValHklm)')" -ForegroundColor Red
$script:Vulnerable = $true
}
$TrustHklm = (Get-ItemProperty -Path $RegistryHklm -Name "TrustPolicy" -ErrorAction SilentlyContinue).TrustPolicy
if ($TrustHklm -eq 2) {
Write-Host " - HKLM WSH TrustPolicy: 2 (Secure)" -ForegroundColor Green
} else {
Write-Host " - VULNERABLE: HKLM WSH TrustPolicy is not set to 2 (Value: '$($TrustHklm)')" -ForegroundColor Red
$script:Vulnerable = $true
}
} else {
Write-Host " - VULNERABLE: HKLM WSH settings key is missing (Expected: Enabled = 0, TrustPolicy = 2)" -ForegroundColor Red
$script:Vulnerable = $true
}
# 2. Audit WSH Registry settings in WOW6432Node on 64-bit systems
if ([Environment]::Is64BitOperatingSystem) {
$RegistryWow64 = "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Script Host\Settings"
if (Test-Path $RegistryWow64) {
$ValWow64 = (Get-ItemProperty -Path $RegistryWow64 -Name "Enabled" -ErrorAction SilentlyContinue).Enabled
if ($ValWow64 -eq 0) {
Write-Host " - WOW6432Node WSH Enabled: 0 (Secure)" -ForegroundColor Green
} else {
Write-Host " - VULNERABLE: WOW6432Node WSH is enabled or not configured (Value: '$($ValWow64)')" -ForegroundColor Red
$script:Vulnerable = $true
}
$TrustWow64 = (Get-ItemProperty -Path $RegistryWow64 -Name "TrustPolicy" -ErrorAction SilentlyContinue).TrustPolicy
if ($TrustWow64 -eq 2) {
Write-Host " - WOW6432Node WSH TrustPolicy: 2 (Secure)" -ForegroundColor Green
} else {
Write-Host " - VULNERABLE: WOW6432Node WSH TrustPolicy is not set to 2 (Value: '$($TrustWow64)')" -ForegroundColor Red
$script:Vulnerable = $true
}
} else {
Write-Host " - VULNERABLE: WOW6432Node WSH settings key is missing (Expected: Enabled = 0, TrustPolicy = 2)" -ForegroundColor Red
$script:Vulnerable = $true
}
}
# 3. Audit file associations
$Extensions = @("vbs", "vbe", "js", "jse", "wsf", "wsh", "hta")
foreach ($Ext in $Extensions) {
$ProgIdPath = "HKLM:\SOFTWARE\Classes\.$Ext"
if (Test-Path $ProgIdPath) {
$Handler = (Get-ItemProperty -Path $ProgIdPath -Name "" -ErrorAction SilentlyContinue).""
if ($Handler -eq "txtfile" -or $Handler -match "notepad") {
Write-Host " - Extension .$Ext Handler: $Handler (Secure)" -ForegroundColor Green
} else {
Write-Host " - VULNERABLE: Extension .$Ext Handler is '$($Handler)' (Expected: txtfile/notepad)" -ForegroundColor Red
$script:Vulnerable = $true
}
} else {
Write-Host " - VULNERABLE: Extension .$Ext Class Registry key not found." -ForegroundColor Red
$script:Vulnerable = $true
}
}
if ($script:Vulnerable) {
Write-Host "[-] Audit Result: VULNERABLE - Windows Script Host hardening controls on Domain Controller do not meet baseline requirements." -ForegroundColor Red
} else {
Write-Host "[+] Audit Result: SECURE - Windows Script Host hardening controls on Domain Controller are fully compliant." -ForegroundColor Green
}
Sources & Compliance References
- ANSSI AD Hardening Guide: Recommendations Section 3.1.2 (System hardening and OS minimization) / DAT-NT-13 Note Technique.
- DoD Windows Server STIG: Requirements for unauthorized software and script execution control.
- DoD Windows 11 Computer STIG v2r6: Rule
V-219661(Windows Script Host must be disabled). - CIS Microsoft Windows Server Benchmark: Section 18.9 (Administrative Templates: System - Script Execution Restrictions).
- Microsoft Learn: Active Directory-Based Activation Overview and Software Licensing CIM Provider.