Windows Hardening Guide

Secure Windows servers and workstations against attacks

Windows security
By FixTheVuln Team Peer-reviewed security content Sources: CISA, NVD, OWASP

Key Takeaways

  • Enable Windows Defender and keep definitions updated automatically
  • Use Group Policy to enforce strong password policies and account lockout
  • Disable unnecessary services like Remote Desktop unless required
  • Enable BitLocker for full disk encryption on all endpoints
  • Configure Windows Firewall to block all inbound by default
Why Windows Hardening Matters: Windows is the most targeted operating system. Default configurations leave systems vulnerable to malware, ransomware, and credential theft. Hardening reduces attack surface and improves detection capabilities.

Windows Updates

1. Keep Windows Updated

PowerShell Commands

# Check for updates (PowerShell as Admin) Install-Module PSWindowsUpdate -Force Import-Module PSWindowsUpdate # List available updates Get-WindowsUpdate # Install all updates Install-WindowsUpdate -AcceptAll -AutoReboot # Check update history Get-WUHistory | Select-Object -First 20 # Configure Windows Update via Registry Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "AUOptions" -Value 4 Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "ScheduledInstallDay" -Value 0 Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU" -Name "ScheduledInstallTime" -Value 3

Group Policy (gpedit.msc)

Computer Configuration → Administrative Templates → Windows Components → Windows Update

  • Configure Automatic Updates: Enabled (Auto download and schedule install)
  • Specify intranet Microsoft update service location (for WSUS)

User Account Security

2. Secure User Accounts

Rename/Disable Default Accounts

# PowerShell - Rename Administrator account Rename-LocalUser -Name "Administrator" -NewName "LocalAdmin" # Disable Guest account Disable-LocalUser -Name "Guest" # Check for accounts with no password Get-LocalUser | Where-Object { $_.PasswordRequired -eq $false } # Force password change on next login Set-LocalUser -Name "username" -PasswordNeverExpires $false net user username /logonpasswordchg:yes # List all local users Get-LocalUser | Select-Object Name, Enabled, PasswordRequired, LastLogon # List local admins Get-LocalGroupMember -Group "Administrators"

Password Policy (secpol.msc or Group Policy)

# View current password policy net accounts # Set password policy via command line net accounts /minpwlen:12 net accounts /maxpwage:90 net accounts /minpwage:1 net accounts /uniquepw:5 # Or via PowerShell/Group Policy # Computer Configuration → Windows Settings → Security Settings → Account Policies → Password Policy # Recommended settings: # - Minimum password length: 12 characters # - Password must meet complexity requirements: Enabled # - Maximum password age: 90 days # - Minimum password age: 1 day # - Enforce password history: 5 passwords

Account Lockout Policy

# Computer Configuration → Windows Settings → Security Settings → Account Policies → Account Lockout Policy # Account lockout threshold: 5 invalid attempts # Account lockout duration: 30 minutes # Reset account lockout counter after: 30 minutes # PowerShell net accounts /lockoutthreshold:5 net accounts /lockoutduration:30 net accounts /lockoutwindow:30

Windows Firewall

3. Configure Windows Firewall

Enable and Configure Firewall

# PowerShell - Check firewall status Get-NetFirewallProfile | Select-Object Name, Enabled # Enable all profiles Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True # Set default to block inbound Set-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block -DefaultOutboundAction Allow # Allow specific port New-NetFirewallRule -DisplayName "Allow RDP" -Direction Inbound -Protocol TCP -LocalPort 3389 -Action Allow # Allow application New-NetFirewallRule -DisplayName "Allow MyApp" -Direction Inbound -Program "C:\Apps\myapp.exe" -Action Allow # Allow from specific IP only New-NetFirewallRule -DisplayName "Allow SSH from Admin" -Direction Inbound -Protocol TCP -LocalPort 22 -RemoteAddress 192.168.1.100 -Action Allow # Block outbound to specific IP New-NetFirewallRule -DisplayName "Block Malicious IP" -Direction Outbound -RemoteAddress 203.0.113.50 -Action Block # List all rules Get-NetFirewallRule | Where-Object { $_.Enabled -eq 'True' } | Select-Object DisplayName, Direction, Action # Remove a rule Remove-NetFirewallRule -DisplayName "Allow RDP" # Export firewall rules netsh advfirewall export "C:\firewall-backup.wfw" # Import firewall rules netsh advfirewall import "C:\firewall-backup.wfw"

Firewall Logging

# Enable firewall logging Set-NetFirewallProfile -Profile Domain,Public,Private -LogAllowed True -LogBlocked True -LogFileName "%systemroot%\system32\LogFiles\Firewall\pfirewall.log" -LogMaxSizeKilobytes 32767 # View firewall logs Get-Content "$env:systemroot\system32\LogFiles\Firewall\pfirewall.log" -Tail 50

Remote Desktop Security

4. Secure Remote Desktop (RDP)

RDP Best Practices

# Disable RDP if not needed Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server" -Name "fDenyTSConnections" -Value 1 # Enable RDP (if needed) Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server" -Name "fDenyTSConnections" -Value 0 # Enable Network Level Authentication (NLA) - CRITICAL Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" -Name "UserAuthentication" -Value 1 # Change RDP port (security through obscurity) Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" -Name "PortNumber" -Value 3390 # Limit RDP access to specific users # Computer Management → Local Users and Groups → Groups → Remote Desktop Users Add-LocalGroupMember -Group "Remote Desktop Users" -Member "rdp_admin" Remove-LocalGroupMember -Group "Remote Desktop Users" -Member "Everyone" # Set idle timeout (Group Policy) # Computer Configuration → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Session Host → Session Time Limits # Set idle session limit: 15 minutes

RDP Gateway (for Internet-facing RDP)

Instead of exposing RDP directly to the internet:

  • Use RDP Gateway with SSL/TLS
  • Use VPN to access internal RDP
  • Use Azure Bastion for Azure VMs
  • Implement MFA for RDP access

Windows Defender

5. Configure Windows Defender

Enable All Protections

# Check Defender status Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled, IoavProtectionEnabled, AntispywareEnabled, BehaviorMonitorEnabled # Enable Real-time protection Set-MpPreference -DisableRealtimeMonitoring $false # Enable cloud-delivered protection Set-MpPreference -MAPSReporting Advanced Set-MpPreference -SubmitSamplesConsent SendAllSamples # Enable Potentially Unwanted Application (PUA) protection Set-MpPreference -PUAProtection Enabled # Enable Network Protection Set-MpPreference -EnableNetworkProtection Enabled # Update definitions Update-MpSignature # Run full scan Start-MpScan -ScanType FullScan # Schedule daily quick scan Set-MpPreference -ScanScheduleQuickScanTime 12:00:00 # View threat history Get-MpThreatDetection | Select-Object -First 10

Attack Surface Reduction (ASR) Rules

# Enable ASR rules (Windows 10/11 Enterprise, Windows Server 2019+) # Block executable content from email and webmail Add-MpPreference -AttackSurfaceReductionRules_Ids BE9BA2D9-53EA-4CDC-84E5-9B1EEEE46550 -AttackSurfaceReductionRules_Actions Enabled # Block Office apps from creating executable content Add-MpPreference -AttackSurfaceReductionRules_Ids 3B576869-A4EC-4529-8536-B80A7769E899 -AttackSurfaceReductionRules_Actions Enabled # Block Office apps from creating child processes Add-MpPreference -AttackSurfaceReductionRules_Ids D4F940AB-401B-4EFC-AADC-AD5F3C50688A -AttackSurfaceReductionRules_Actions Enabled # Block JavaScript/VBScript from launching downloaded content Add-MpPreference -AttackSurfaceReductionRules_Ids D3E037E1-3EB8-44C8-A917-57927947596D -AttackSurfaceReductionRules_Actions Enabled # Block credential stealing from LSASS Add-MpPreference -AttackSurfaceReductionRules_Ids 9E6C4E1F-7D60-472F-BA1A-A39EF669E4B2 -AttackSurfaceReductionRules_Actions Enabled # View ASR rules status Get-MpPreference | Select-Object -ExpandProperty AttackSurfaceReductionRules_Ids

PowerShell Security

6. Secure PowerShell

Enable Script Logging

# Enable PowerShell Script Block Logging (Group Policy) # Computer Configuration → Administrative Templates → Windows Components → Windows PowerShell # Turn on PowerShell Script Block Logging: Enabled # Or via Registry New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Force Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" -Name "EnableScriptBlockLogging" -Value 1 # Enable Module Logging New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Force Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging" -Name "EnableModuleLogging" -Value 1 # Enable Transcription (logs all PowerShell activity to files) New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" -Force Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" -Name "EnableTranscripting" -Value 1 Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription" -Name "OutputDirectory" -Value "C:\PSTranscripts"

Constrained Language Mode

# Check current language mode $ExecutionContext.SessionState.LanguageMode # Enable Constrained Language Mode (limits dangerous PowerShell features) # Via AppLocker or Windows Defender Application Control (WDAC) # Set execution policy Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine # Block PowerShell 2.0 (lacks security features) Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root

Audit and Logging

7. Enable Security Auditing

Configure Audit Policies

# View current audit policy auditpol /get /category:* # Enable critical audit categories auditpol /set /category:"Account Logon" /success:enable /failure:enable auditpol /set /category:"Account Management" /success:enable /failure:enable auditpol /set /category:"Logon/Logoff" /success:enable /failure:enable auditpol /set /category:"Object Access" /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 # Enable command line auditing (see what commands are run) # Computer Configuration → Administrative Templates → System → Audit Process Creation # Include command line in process creation events: Enabled # Or via Registry Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit" -Name "ProcessCreationIncludeCmdLine_Enabled" -Value 1

Important Event IDs to Monitor

Event ID Description Importance
4624 Successful logon Monitor for unusual logons
4625 Failed logon Brute force detection
4648 Explicit credential logon Pass-the-hash detection
4672 Admin logon Privileged access monitoring
4688 Process creation Malware execution
4698 Scheduled task created Persistence mechanism
4720 User account created Unauthorized access
4732 Member added to local group Privilege escalation
7045 Service installed Persistence/malware

View Security Logs

# PowerShell - View recent security events Get-WinEvent -LogName Security -MaxEvents 100 | Select-Object TimeCreated, Id, Message # Search for failed logons Get-WinEvent -FilterHashtable @{LogName='Security';Id=4625} -MaxEvents 50 # Search for admin logons Get-WinEvent -FilterHashtable @{LogName='Security';Id=4672} -MaxEvents 50 # Export events Get-WinEvent -LogName Security -MaxEvents 1000 | Export-Csv "C:\security-events.csv"

Additional Hardening

8. Additional Security Settings

Disable SMBv1

# Check SMB versions Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol, EnableSMB2Protocol # Disable SMBv1 (vulnerable to WannaCry, EternalBlue) Set-SmbServerConfiguration -EnableSMB1Protocol $false -Force # Or via DISM Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol # Disable SMBv1 client Set-SmbClientConfiguration -EnableSMB1Protocol $false

Enable Credential Guard (Enterprise)

# Check if Credential Guard is running Get-CimInstance -ClassName Win32_DeviceGuard -Namespace root\Microsoft\Windows\DeviceGuard # Enable via Group Policy # Computer Configuration → Administrative Templates → System → Device Guard # Turn On Virtualization Based Security: Enabled # Credential Guard Configuration: Enabled with UEFI lock

BitLocker Encryption

# Check BitLocker status Get-BitLockerVolume # Enable BitLocker on C: drive Enable-BitLocker -MountPoint "C:" -EncryptionMethod XtsAes256 -UsedSpaceOnly -RecoveryPasswordProtector # Add TPM protector Add-BitLockerKeyProtector -MountPoint "C:" -TpmProtector # Backup recovery key to AD (domain-joined) Backup-BitLockerKeyProtector -MountPoint "C:" -KeyProtectorId (Get-BitLockerVolume -MountPoint "C:").KeyProtector[0].KeyProtectorId

Disable LLMNR and NBT-NS (Prevent Responder attacks)

# Disable LLMNR via Registry New-Item -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Force Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" -Name "EnableMulticast" -Value 0 # Disable NBT-NS (per adapter) $adapters = Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object { $_.IPEnabled -eq $true } foreach ($adapter in $adapters) { $adapter.SetTcpipNetbios(2) # 2 = Disable NetBIOS over TCP/IP }

Security Checklist

☐ Windows fully updated with automatic updates
☐ Administrator account renamed and strong password set
☐ Guest account disabled
☐ Strong password policy enforced
☐ Account lockout policy configured
☐ Windows Firewall enabled on all profiles
☐ RDP secured with NLA or disabled if not needed
☐ Windows Defender enabled with all protections
☐ Attack Surface Reduction rules enabled
☐ PowerShell logging enabled
☐ Security auditing configured
☐ SMBv1 disabled
☐ BitLocker encryption enabled
☐ LLMNR and NBT-NS disabled

Important: Test all changes in a non-production environment first. Some security settings may impact application functionality. Always have a recovery plan before making Group Policy changes.

Related Resources

🐧 Linux Hardening Linux server security 📊 Log Management Logging and SIEM basics 🔑 Password Policy NIST password guidelines

Test Your Knowledge

Security+ Practice Quiz CySA+ Practice Quiz
← Back to Tools

FixTheVuln Store

Get the CompTIA Security+ Study Planner

Fillable PDF study planners with domain trackers, weekly schedules, and progress tracking. Available in Standard, ADHD-Friendly, Dark Mode, and 4-Format Bundle.

CompTIA Security+ Planner

60+ certifications available — from $5.99

CyberFolio

Choosing your next cert? Track them all in one place.

Build a shareable cybersecurity portfolio that highlights your certifications, projects, and skills — free.

Build Your Portfolio →