DevOps12 min readJanuary 15, 2024

Hardening Windows 11: Essential Security Configuration Guide

Complete guide to hardening Windows 11 with GPOs, ASR rules, PowerShell scripts, and security best practices for enterprise and home users.

TL;DR

Summary not available.

TL;DR

This guide provides a comprehensive approach to hardening Windows 11 systems using Group Policy Objects (GPOs), Attack Surface Reduction (ASR) rules, and PowerShell automation. We'll cover essential security configurations that can reduce attack vectors by up to 80% when properly implemented.

Introduction

Windows 11 introduced several security improvements over its predecessors, but out-of-the-box configurations often prioritize usability over security. This guide will walk you through essential hardening steps that every system administrator should implement, whether managing enterprise environments or securing personal systems.

Security Baseline Overview

Before diving into specific configurations, let's establish our security baseline priorities:

  1. Principle of Least Privilege: Users and processes should have minimal necessary permissions
  2. Defense in Depth: Multiple layers of security controls
  3. Attack Surface Reduction: Minimize exposed services and features
  4. Monitoring and Logging: Comprehensive audit trails
  5. Regular Updates: Automated patching and vulnerability management

Group Policy Configuration

Essential GPO Settings

Let's start with the most critical Group Policy settings that should be implemented on every Windows 11 system:

User Account Control (UAC)

# PowerShell script to configure UAC via registry
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "ConsentPromptBehaviorAdmin" -Value 2
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "ConsentPromptBehaviorUser" -Value 3
Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA" -Value 1

GPO Path: Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options

Key settings:

  • User Account Control: Behavior of the elevation prompt for administrators: Set to "Prompt for consent on the secure desktop"
  • User Account Control: Behavior of the elevation prompt for standard users: Set to "Prompt for credentials on the secure desktop"

Windows Defender Configuration

# Enable Windows Defender real-time protection
Set-MpPreference -DisableRealtimeMonitoring $false
Set-MpPreference -DisableBehaviorMonitoring $false
Set-MpPreference -DisableBlockAtFirstSeen $false
Set-MpPreference -DisableIOAVProtection $false
Set-MpPreference -DisableScriptScanning $false

GPO Path: Computer Configuration > Policies > Administrative Templates > Windows Components > Microsoft Defender Antivirus

Advanced Security Policies

Audit Policy Configuration

Comprehensive logging is crucial for security monitoring:

# Configure advanced audit policies
auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable
auditpol /set /category:"Account Logon" /success:enable /failure:enable
auditpol /set /category:"Account Management" /success:enable /failure:enable
auditpol /set /category:"Policy Change" /success:enable /failure:enable
auditpol /set /category:"Privilege Use" /success:enable /failure:enable
auditpol /set /category:"System" /success:enable /failure:enable

Network Security

# Disable SMBv1 protocol (major security risk)
Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol -NoRestart
 
# Configure SMB security
Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force
Set-SmbServerConfiguration -RequireSecuritySignature $true -Force

Attack Surface Reduction (ASR) Rules

ASR rules are one of the most effective ways to prevent common attack vectors. Here's how to implement them:

PowerShell ASR Configuration

# Function to configure ASR rules
function Set-ASRRules {
    $ASRRules = @{
        # Block executable content from email client and webmail
        "BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550" = "Enabled"
        
        # Block all Office applications from creating child processes
        "D4F940AB-401B-4EFC-AADC-AD5F3C50688A" = "Enabled"
        
        # Block Office applications from creating executable content
        "3B576869-A4EC-4529-8536-B80A7769E899" = "Enabled"
        
        # Block Office applications from injecting code into other processes
        "75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84" = "Enabled"
        
        # Block JavaScript or VBScript from launching downloaded executable content
        "D3E037E1-3EB8-44C8-A917-57927947596D" = "Enabled"
        
        # Block execution of potentially obfuscated scripts
        "5BEB7EFE-FD9A-4556-801D-275E5FFC04CC" = "Enabled"
        
        # Block Win32 API calls from Office macros
        "92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B" = "Enabled"
        
        # Block process creations originating from PSExec and WMI commands
        "D1E49AAC-8F56-4280-B9BA-993A6D77406C" = "Enabled"
        
        # Block untrusted and unsigned processes that run from USB
        "B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4" = "Enabled"
        
        # Use advanced protection against ransomware
        "C1DB55AB-C21A-4637-BB3F-A12568109D35" = "Enabled"
    }
    
    foreach ($Rule in $ASRRules.GetEnumerator()) {
        try {
            Add-MpPreference -AttackSurfaceReductionRules_Ids $Rule.Key -AttackSurfaceReductionRules_Actions $Rule.Value
            Write-Host "Successfully configured ASR rule: $($Rule.Key)" -ForegroundColor Green
        }
        catch {
            Write-Warning "Failed to configure ASR rule: $($Rule.Key) - $($_.Exception.Message)"
        }
    }
}
 
# Execute the function
Set-ASRRules

ASR Rule Monitoring

# Script to check ASR rule effectiveness
function Get-ASRRuleStatus {
    $ASRRules = Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids
    $ASRActions = Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Actions
    
    if ($ASRRules.Count -eq 0) {
        Write-Host "No ASR rules configured" -ForegroundColor Yellow
        return
    }
    
    for ($i = 0; $i -lt $ASRRules.Count; $i++) {
        $RuleName = switch ($ASRRules[$i]) {
            "BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550" { "Block executable content from email" }
            "D4F940AB-401B-4EFC-AADC-AD5F3C50688A" { "Block Office child processes" }
            "3B576869-A4EC-4529-8536-B80A7769E899" { "Block Office executable content" }
            "75668C1F-73B5-4CF0-BB93-3ECF5CB7CC84" { "Block Office code injection" }
            "D3E037E1-3EB8-44C8-A917-57927947596D" { "Block script-launched executables" }
            "5BEB7EFE-FD9A-4556-801D-275E5FFC04CC" { "Block obfuscated scripts" }
            "92E97FA1-2EDF-4476-BDD6-9DD0B4DDDC7B" { "Block Win32 API from Office macros" }
            "D1E49AAC-8F56-4280-B9BA-993A6D77406C" { "Block PSExec/WMI processes" }
            "B2B3F03D-6A65-4F7B-A9C7-1C7EF74A9BA4" { "Block untrusted USB processes" }
            "C1DB55AB-C21A-4637-BB3F-A12568109D35" { "Ransomware protection" }
            default { "Unknown rule" }
        }
        
        $Action = switch ($ASRActions[$i]) {
            "Enabled" { "Enabled" }
            "AuditMode" { "Audit Only" }
            "Disabled" { "Disabled" }
            default { "Unknown" }
        }
        
        Write-Host "$RuleName : $Action" -ForegroundColor $(if ($Action -eq "Enabled") { "Green" } elseif ($Action -eq "Audit Only") { "Yellow" } else { "Red" })
    }
}
 
# Check current ASR status
Get-ASRRuleStatus

Windows Firewall Configuration

Advanced Firewall Rules

# Configure Windows Firewall with advanced security
# Block all inbound connections by default
netsh advfirewall set allprofiles firewallpolicy blockinbound,allowoutbound
 
# Enable logging
netsh advfirewall set allprofiles logging filename "%systemroot%\system32\LogFiles\Firewall\pfirewall.log"
netsh advfirewall set allprofiles logging maxfilesize 4096
netsh advfirewall set allprofiles logging droppedconnections enable
netsh advfirewall set allprofiles logging allowedconnections enable
 
# Block common attack ports
$BlockedPorts = @(135, 139, 445, 1433, 1434, 3389, 5985, 5986)
foreach ($Port in $BlockedPorts) {
    New-NetFirewallRule -DisplayName "Block Port $Port" -Direction Inbound -Protocol TCP -LocalPort $Port -Action Block -Enabled True
}

PowerShell Execution Policy

# Set secure PowerShell execution policy
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine -Force
 
# Enable PowerShell script block logging
$RegPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
if (!(Test-Path $RegPath)) {
    New-Item -Path $RegPath -Force
}
Set-ItemProperty -Path $RegPath -Name "EnableScriptBlockLogging" -Value 1

Service Hardening

Disable Unnecessary Services

# Function to safely disable services
function Disable-UnnecessaryServices {
    $ServicesToDisable = @(
        "Fax",                    # Fax service
        "MapsBroker",            # Downloaded Maps Manager
        "lfsvc",                 # Geolocation Service
        "SharedAccess",          # Internet Connection Sharing
        "TrkWks",                # Distributed Link Tracking Client
        "WMPNetworkSvc",         # Windows Media Player Network Sharing
        "XblAuthManager",        # Xbox Live Auth Manager
        "XblGameSave",           # Xbox Live Game Save
        "XboxNetApiSvc"          # Xbox Live Networking Service
    )
    
    foreach ($Service in $ServicesToDisable) {
        try {
            $ServiceObj = Get-Service -Name $Service -ErrorAction SilentlyContinue
            if ($ServiceObj) {
                Stop-Service -Name $Service -Force -ErrorAction SilentlyContinue
                Set-Service -Name $Service -StartupType Disabled
                Write-Host "Disabled service: $Service" -ForegroundColor Green
            }
        }
        catch {
            Write-Warning "Could not disable service: $Service - $($_.Exception.Message)"
        }
    }
}
 
# Execute service hardening
Disable-UnnecessaryServices

Registry Security Hardening

Critical Registry Modifications

# Function to apply security registry settings
function Set-SecurityRegistrySettings {
    $RegistrySettings = @{
        # Disable AutoRun for all drives
        "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\Explorer" = @{
            "NoDriveTypeAutoRun" = 255
        }
        
        # Disable Windows Script Host
        "HKLM:\SOFTWARE\Microsoft\Windows Script Host\Settings" = @{
            "Enabled" = 0
        }
        
        # Enable DEP for all programs
        "HKLM:\SOFTWARE\Policies\Microsoft\Windows\Explorer" = @{
            "NoDataExecutionPrevention" = 0
            "NoHeapTerminationOnCorruption" = 0
        }
        
        # Disable remote registry access
        "HKLM:\SYSTEM\CurrentControlSet\Control\SecurePipeServers\winreg" = @{
            "RemoteRegAccess" = 0
        }
    }
    
    foreach ($RegPath in $RegistrySettings.Keys) {
        if (!(Test-Path $RegPath)) {
            New-Item -Path $RegPath -Force | Out-Null
        }
        
        foreach ($Setting in $RegistrySettings[$RegPath].GetEnumerator()) {
            try {
                Set-ItemProperty -Path $RegPath -Name $Setting.Key -Value $Setting.Value -Force
                Write-Host "Applied registry setting: $RegPath\$($Setting.Key)" -ForegroundColor Green
            }
            catch {
                Write-Warning "Failed to apply registry setting: $RegPath\$($Setting.Key) - $($_.Exception.Message)"
            }
        }
    }
}
 
# Apply registry hardening
Set-SecurityRegistrySettings

BitLocker Configuration

Enable BitLocker with TPM

# Function to enable BitLocker
function Enable-BitLockerProtection {
    # Check if TPM is available
    $TPM = Get-Tpm
    if ($TPM.TpmPresent -and $TPM.TpmReady) {
        try {
            # Enable BitLocker on system drive
            Enable-BitLocker -MountPoint "C:" -EncryptionMethod Aes256 -UsedSpaceOnly -TpmProtector
            
            # Add recovery password protector
            Add-BitLockerKeyProtector -MountPoint "C:" -RecoveryPasswordProtector
            
            Write-Host "BitLocker enabled successfully" -ForegroundColor Green
            
            # Get recovery key
            $RecoveryKey = (Get-BitLockerVolume -MountPoint "C:").KeyProtector | Where-Object {$_.KeyProtectorType -eq "RecoveryPassword"}
            Write-Host "Recovery Key: $($RecoveryKey.RecoveryPassword)" -ForegroundColor Yellow
            Write-Warning "Save this recovery key in a secure location!"
        }
        catch {
            Write-Error "Failed to enable BitLocker: $($_.Exception.Message)"
        }
    }
    else {
        Write-Warning "TPM is not available or ready. BitLocker cannot be enabled."
    }
}
 
# Enable BitLocker if conditions are met
Enable-BitLockerProtection

Monitoring and Compliance

Security Compliance Check Script

# Comprehensive security compliance checker
function Test-SecurityCompliance {
    $ComplianceResults = @()
    
    # Check UAC status
    $UACEnabled = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA").EnableLUA
    $ComplianceResults += [PSCustomObject]@{
        Check = "User Account Control"
        Status = if ($UACEnabled -eq 1) { "PASS" } else { "FAIL" }
        Details = "UAC is $(if ($UACEnabled -eq 1) { 'enabled' } else { 'disabled' })"
    }
    
    # Check Windows Defender status
    $DefenderStatus = Get-MpComputerStatus
    $ComplianceResults += [PSCustomObject]@{
        Check = "Windows Defender Real-time Protection"
        Status = if ($DefenderStatus.RealTimeProtectionEnabled) { "PASS" } else { "FAIL" }
        Details = "Real-time protection is $(if ($DefenderStatus.RealTimeProtectionEnabled) { 'enabled' } else { 'disabled' })"
    }
    
    # Check Windows Update status
    $UpdateService = Get-Service -Name "wuauserv"
    $ComplianceResults += [PSCustomObject]@{
        Check = "Windows Update Service"
        Status = if ($UpdateService.Status -eq "Running") { "PASS" } else { "FAIL" }
        Details = "Windows Update service is $($UpdateService.Status.ToString().ToLower())"
    }
    
    # Check firewall status
    $FirewallProfiles = Get-NetFirewallProfile
    $FirewallEnabled = ($FirewallProfiles | Where-Object {$_.Enabled -eq $false}).Count -eq 0
    $ComplianceResults += [PSCustomObject]@{
        Check = "Windows Firewall"
        Status = if ($FirewallEnabled) { "PASS" } else { "FAIL" }
        Details = "All firewall profiles are $(if ($FirewallEnabled) { 'enabled' } else { 'not enabled' })"
    }
    
    # Check ASR rules
    $ASRRules = Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids
    $ComplianceResults += [PSCustomObject]@{
        Check = "Attack Surface Reduction Rules"
        Status = if ($ASRRules.Count -gt 0) { "PASS" } else { "FAIL" }
        Details = "$($ASRRules.Count) ASR rules configured"
    }
    
    # Display results
    Write-Host "`nSecurity Compliance Results:" -ForegroundColor Cyan
    Write-Host "=" * 50 -ForegroundColor Cyan
    
    $ComplianceResults | ForEach-Object {
        $Color = if ($_.Status -eq "PASS") { "Green" } else { "Red" }
        Write-Host "[$($_.Status)]" -ForegroundColor $Color -NoNewline
        Write-Host " $($_.Check): $($_.Details)"
    }
    
    $PassCount = ($ComplianceResults | Where-Object {$_.Status -eq "PASS"}).Count
    $TotalCount = $ComplianceResults.Count
    $CompliancePercentage = [math]::Round(($PassCount / $TotalCount) * 100, 2)
    
    Write-Host "`nOverall Compliance: $CompliancePercentage% ($PassCount/$TotalCount)" -ForegroundColor $(if ($CompliancePercentage -ge 80) { "Green" } elseif ($CompliancePercentage -ge 60) { "Yellow" } else { "Red" })
}
 
# Run compliance check
Test-SecurityCompliance

Automated Hardening Script

Here's a comprehensive script that applies all the hardening measures:

# Windows 11 Hardening Master Script
param(
    [switch]$SkipASR,
    [switch]$SkipBitLocker,
    [switch]$TestMode
)
 
function Write-HardeningLog {
    param([string]$Message, [string]$Level = "INFO")
    $Timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $LogMessage = "[$Timestamp] [$Level] $Message"
    Write-Host $LogMessage -ForegroundColor $(
        switch ($Level) {
            "ERROR" { "Red" }
            "WARNING" { "Yellow" }
            "SUCCESS" { "Green" }
            default { "White" }
        }
    )
}
 
# Main hardening function
function Start-WindowsHardening {
    Write-HardeningLog "Starting Windows 11 hardening process..." "SUCCESS"
    
    if ($TestMode) {
        Write-HardeningLog "Running in TEST MODE - no changes will be made" "WARNING"
        return
    }
    
    try {
        # Apply UAC settings
        Write-HardeningLog "Configuring User Account Control..."
        Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "ConsentPromptBehaviorAdmin" -Value 2
        Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" -Name "EnableLUA" -Value 1
        
        # Configure Windows Defender
        Write-HardeningLog "Configuring Windows Defender..."
        Set-MpPreference -DisableRealtimeMonitoring $false
        Set-MpPreference -DisableBehaviorMonitoring $false
        Set-MpPreference -DisableBlockAtFirstSeen $false
        
        # Apply ASR rules if not skipped
        if (-not $SkipASR) {
            Write-HardeningLog "Applying Attack Surface Reduction rules..."
            Set-ASRRules
        }
        
        # Configure firewall
        Write-HardeningLog "Configuring Windows Firewall..."
        netsh advfirewall set allprofiles firewallpolicy blockinbound,allowoutbound | Out-Null
        
        # Disable unnecessary services
        Write-HardeningLog "Disabling unnecessary services..."
        Disable-UnnecessaryServices
        
        # Apply registry hardening
        Write-HardeningLog "Applying registry security settings..."
        Set-SecurityRegistrySettings
        
        # Enable BitLocker if not skipped
        if (-not $SkipBitLocker) {
            Write-HardeningLog "Configuring BitLocker..."
            Enable-BitLockerProtection
        }
        
        Write-HardeningLog "Windows 11 hardening completed successfully!" "SUCCESS"
        Write-HardeningLog "System restart recommended to ensure all changes take effect." "WARNING"
        
    }
    catch {
        Write-HardeningLog "Error during hardening process: $($_.Exception.Message)" "ERROR"
    }
}
 
# Execute hardening
Start-WindowsHardening

Verification and Testing

Security Validation Checklist

After applying these hardening measures, verify your configuration:

  1. Run Windows Security Assessment:

    Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, TotalPhysicalMemory
    Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled, IoavProtectionEnabled
  2. Test ASR Rules:

    • Download EICAR test file to verify antivirus detection
    • Test Office macro blocking with sample malicious documents
    • Verify script execution policies are enforced
  3. Validate Network Security:

    Get-NetFirewallProfile | Select-Object Name, Enabled
    Get-NetFirewallRule | Where-Object {$_.Enabled -eq $true -and $_.Direction -eq "Inbound"} | Select-Object DisplayName, Action

Key Takeaways

  1. Layered Security: No single security measure is sufficient; implement multiple overlapping controls
  2. Regular Updates: Keep systems patched and security configurations current
  3. Monitoring: Implement comprehensive logging and regular security assessments
  4. User Training: Technical controls must be complemented by user awareness
  5. Testing: Always test hardening measures in non-production environments first
  6. Documentation: Maintain detailed records of all security configurations
  7. Compliance: Regularly verify that hardening measures remain effective

Conclusion

Windows 11 hardening is an ongoing process that requires careful planning, implementation, and maintenance. The configurations outlined in this guide provide a solid security foundation, but remember that security is not a one-time setup—it requires continuous monitoring and updates.

Start with the most critical settings (UAC, Windows Defender, Firewall) and gradually implement additional hardening measures based on your risk assessment and organizational requirements. Always test changes in a controlled environment before deploying to production systems.

Regular security assessments and compliance checks will help ensure your hardening measures remain effective against evolving threats. Consider implementing automated scripts to maintain consistent security configurations across your environment.


Remember: Security is a journey, not a destination. Stay informed about emerging threats and update your hardening strategies accordingly.

Tags

#Windows#Security#GPO#PowerShell#Hardening#ASR
Was this helpful?