Forked from jbratu/setupiisforsslperfectforwardsecrecy_v17.ps1
Last active
October 30, 2025 00:19
-
-
Save Paxilein/b636766c74b7fa09d8deafb67bd274b9 to your computer and use it in GitHub Desktop.
Great PowerShell script for tightening HTTPS security on IIS and disabling insecure protocols and ciphers. Now supporting TLS 1.3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #Requires -RunAsAdministrator | |
| # Original script (up to 2019): Copyright Alexander Hass | |
| # https://www.hass.de/content/setup-microsoft-windows-or-iis-ssl-perfect-forward-secrecy-and-tls-12 | |
| # | |
| # 2022 update (v3.0.2): Markus Kepert | |
| # https://gist.github.com/MarkusKepert | |
| # | |
| # 2025 update (v4.0.0): Pax | |
| # | |
| # After running this script the computer only supports: | |
| # - TLS 1.2 | |
| # - TLS 1.3 (if supported by the OS) | |
| # | |
| # Version 4.0.0 - Updated October 2025 | |
| Write-Host 'Configuring IIS with SSL/TLS Deployment Best Practices...' | |
| Write-Host '--------------------------------------------------------------------------------' | |
| # Detect OS version first to optimize configuration | |
| # This avoids trying to disable protocols that don't exist on modern systems | |
| $os = Get-CimInstance -ClassName Win32_OperatingSystem | |
| $osBuildNumber = [int]$os.BuildNumber | |
| $productType = $os.ProductType # 1=Workstation, 2=Domain Controller, 3=Server | |
| $isModernOS = $osBuildNumber -ge 14393 # Windows 10 1607 / Server 2016 or newer | |
| $supportsTLS13 = $false | |
| $osName = "" | |
| # Determine OS name and TLS 1.3 support | |
| if ($productType -eq 1) { | |
| # Workstation (Client OS) | |
| if ($osBuildNumber -ge 22000) { | |
| $supportsTLS13 = $true | |
| $osName = "Windows 11 (Build $osBuildNumber)" | |
| } elseif ($osBuildNumber -ge 10240) { | |
| $osName = "Windows 10 (Build $osBuildNumber)" | |
| } else { | |
| $osName = "Windows (Build $osBuildNumber)" | |
| } | |
| } else { | |
| # Server or Domain Controller | |
| if ($osBuildNumber -ge 26040) { | |
| $supportsTLS13 = $true | |
| $osName = "Windows Server 2025 (Build $osBuildNumber)" | |
| } elseif ($osBuildNumber -ge 20348) { | |
| $supportsTLS13 = $true | |
| $osName = "Windows Server 2022 (Build $osBuildNumber)" | |
| } elseif ($osBuildNumber -ge 17763) { | |
| $osName = "Windows Server 2019 (Build $osBuildNumber)" | |
| } elseif ($osBuildNumber -ge 14393) { | |
| $osName = "Windows Server 2016 (Build $osBuildNumber)" | |
| } else { | |
| $osName = "Windows Server (Build $osBuildNumber)" | |
| } | |
| } | |
| Write-Host "Detected OS: $osName" | |
| Write-Host '--------------------------------------------------------------------------------' | |
| # Disable legacy protocols (only on older systems where they still exist) | |
| if (-not $isModernOS) { | |
| # Disable Multi-Protocol Unified Hello (legacy systems only) | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\Multi-Protocol Unified Hello\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\Multi-Protocol Unified Hello\Server' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\Multi-Protocol Unified Hello\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\Multi-Protocol Unified Hello\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\Multi-Protocol Unified Hello\Client' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\Multi-Protocol Unified Hello\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'Multi-Protocol Unified Hello has been disabled.' -ForegroundColor Green | |
| # Disable PCT 1.0 (legacy systems only) | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Server' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Client' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\PCT 1.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'PCT 1.0 has been disabled.' -ForegroundColor Green | |
| # Disable SSL 2.0 (legacy systems only - removed entirely in Windows 10 1607+/Server 2016+) | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 2.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'SSL 2.0 has been disabled.' -ForegroundColor Green | |
| } | |
| # Disable SSL 3.0 (all systems - still present but disabled by default on modern systems) | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'SSL 3.0 has been disabled.' -ForegroundColor Green | |
| # Disable TLS 1.0 for client and server SCHANNEL communications | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.0\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'TLS 1.0 has been disabled.' -ForegroundColor Green | |
| # Add and Disable TLS 1.1 for client and server SCHANNEL communications | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Server' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client' -name 'Enabled' -value '0' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.1\Client' -name 'DisabledByDefault' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'TLS 1.1 has been disabled.' -ForegroundColor Green | |
| # Add and Enable TLS 1.2 for client and server SCHANNEL communications | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'TLS 1.2 has been enabled.' -ForegroundColor Green | |
| # Add and Enable TLS 1.3 for client and server SCHANNEL communications | |
| # Per Microsoft documentation: https://learn.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp- | |
| # TLS 1.3 is ONLY supported on Windows 11, Windows Server 2022, and Windows Server 2025 | |
| # "Enabling TLS 1.3 on earlier versions of Windows is not a safe system configuration" | |
| if ($supportsTLS13) { | |
| Write-Host "TLS 1.3: $osName detected - enabling TLS 1.3." -ForegroundColor Green | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Server' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| New-Item 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client' -name 'DisabledByDefault' -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host 'TLS 1.3 has been enabled.' -ForegroundColor Green | |
| } else { | |
| Write-Host "TLS 1.3: $osName detected - TLS 1.3 is NOT supported on this OS version." -ForegroundColor Yellow | |
| Write-Host " TLS 1.3 is only available on Windows 11, Windows Server 2022, or Windows Server 2025." -ForegroundColor Yellow | |
| Write-Host " Per Microsoft: 'Enabling TLS 1.3 on earlier versions is not a safe system configuration.'" -ForegroundColor Yellow | |
| Write-Host " System will use TLS 1.2 (which remains secure and widely supported)." -ForegroundColor Cyan | |
| Write-Host " See: https://learn.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp-" -ForegroundColor Cyan | |
| } | |
| # Re-create the ciphers key. | |
| New-Item 'HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers' -Force | Out-Null | |
| # Disable insecure/weak ciphers. | |
| $insecureCiphers = @( | |
| 'DES 56/56', | |
| 'NULL', | |
| 'RC2 128/128', | |
| 'RC2 40/128', | |
| 'RC2 56/128', | |
| 'RC4 40/128', | |
| 'RC4 56/128', | |
| 'RC4 64/128', | |
| 'RC4 128/128', | |
| 'Triple DES 168' | |
| ) | |
| Foreach ($insecureCipher in $insecureCiphers) { | |
| $key = (Get-Item HKLM:\).OpenSubKey('SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers', $true).CreateSubKey($insecureCipher) | |
| $key.SetValue('Enabled', 0, 'DWord') | |
| $key.close() | |
| Write-Host "Weak cipher $insecureCipher has been disabled." -ForegroundColor Green | |
| } | |
| # Enable new secure ciphers. | |
| # - RC4: It is recommended to disable RC4, but you may lock out WinXP/IE8 if you enforce this. This is a requirement for FIPS 140-2. | |
| # - 3DES: It is recommended to disable these in near future. This is the last cipher supported by Windows XP. | |
| # - Windows Vista and before 'Triple DES 168' was named 'Triple DES 168/168' per https://support.microsoft.com/en-us/kb/245030 | |
| $secureCiphers = @( | |
| 'AES 128/128', | |
| 'AES 256/256' | |
| ) | |
| Foreach ($secureCipher in $secureCiphers) { | |
| $key = (Get-Item HKLM:\).OpenSubKey('SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers', $true).CreateSubKey($secureCipher) | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Ciphers\$secureCipher" -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| $key.close() | |
| Write-Host "Strong cipher $secureCipher has been enabled." -ForegroundColor Green | |
| } | |
| # Set hashes configuration. | |
| New-Item 'HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes' -Force | Out-Null | |
| # Disable weak hash algorithms | |
| $weakHashes = @( | |
| 'MD5', | |
| 'SHA' # SHA-1 is deprecated due to collision attacks (SHAttered) - only needed for TLS 1.0/1.1 which we disable | |
| ) | |
| Foreach ($weakHash in $weakHashes) { | |
| New-Item "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\$weakHash" -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\$weakHash" -name Enabled -value 0 -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host "Weak hash $weakHash has been disabled." -ForegroundColor Green | |
| } | |
| # Enable secure hash algorithms (SHA-2 family) | |
| $secureHashes = @( | |
| 'SHA256', | |
| 'SHA384', | |
| 'SHA512' | |
| ) | |
| Foreach ($secureHash in $secureHashes) { | |
| $key = (Get-Item HKLM:\).OpenSubKey('SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes', $true).CreateSubKey($secureHash) | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Hashes\$secureHash" -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| $key.close() | |
| Write-Host "Hash $secureHash has been enabled." -ForegroundColor Green | |
| } | |
| # Set KeyExchangeAlgorithms configuration. | |
| New-Item 'HKLM:SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms' -Force | Out-Null | |
| $secureKeyExchangeAlgorithms = @( | |
| 'Diffie-Hellman', | |
| 'ECDH', | |
| 'PKCS' | |
| ) | |
| Foreach ($secureKeyExchangeAlgorithm in $secureKeyExchangeAlgorithms) { | |
| $key = (Get-Item HKLM:\).OpenSubKey('SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms', $true).CreateSubKey($secureKeyExchangeAlgorithm) | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\$secureKeyExchangeAlgorithm" -name 'Enabled' -value '0xffffffff' -PropertyType 'DWord' -Force | Out-Null | |
| $key.close() | |
| Write-Host "KeyExchangeAlgorithm $secureKeyExchangeAlgorithm has been enabled." -ForegroundColor Green | |
| } | |
| # Microsoft Security Advisory 3174644 - Updated Support for Diffie-Hellman Key Exchange | |
| # https://docs.microsoft.com/en-us/security-updates/SecurityAdvisories/2016/3174644 | |
| Write-Host 'Configure longer DHE key shares for TLS servers.' | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman" -name 'ServerMinKeyBitLength' -value '2048' -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman" -name 'ClientMinKeyBitLength' -value '2048' -PropertyType 'DWord' -Force | Out-Null | |
| # https://support.microsoft.com/en-us/help/3174644/microsoft-security-advisory-updated-support-for-diffie-hellman-key-exc | |
| New-ItemProperty -path "HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\PKCS" -name 'ClientMinKeyBitLength' -value '2048' -PropertyType 'DWord' -Force | Out-Null | |
| # Set cipher suites order as secure as possible (Enables Perfect Forward Secrecy). | |
| if ($osBuildNumber -lt 9200) { | |
| # Windows 2008 R2 and earlier (build < 9200) | |
| Write-Host 'Use cipher suites order for Windows 2008/2008R2 or older.' | |
| $cipherSuitesOrder = @( | |
| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P521', | |
| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384', | |
| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P256', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P521', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P384', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256', | |
| # Note: Removed ECDHE CBC_SHA (SHA-1) cipher suites - not usable with SHA-1 disabled | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P521', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384_P384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P521', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256_P256', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P521', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384_P384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P521', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256_P256', | |
| # Note: Removed ECDSA CBC_SHA (SHA-1) cipher suites - not usable with SHA-1 disabled | |
| # Below are the only AEAD ciphers available on Windows 2012R2 and earlier. | |
| # - RSA certificates need below ciphers, but ECDSA certificates (EV) may not. | |
| # - We get penalty for not using AEAD suites with RSA certificates. | |
| 'TLS_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_RSA_WITH_AES_128_GCM_SHA256', | |
| 'TLS_RSA_WITH_AES_256_CBC_SHA256', | |
| 'TLS_RSA_WITH_AES_128_CBC_SHA256', | |
| # Note: Removed RSA CBC_SHA (SHA-1) cipher suites - not usable with SHA-1 disabled | |
| 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256' | |
| ) | |
| } elseif ($osBuildNumber -ge 20348) { | |
| # Windows Server 2022 (build 20348+), Server 2025 (build 26040+), Windows 11 (build 22000+) | |
| # Based on official Microsoft documentation: | |
| # https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022 | |
| # https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2025 | |
| Write-Host 'Use cipher suites order for Windows Server 2022/2025 and Windows 11 or newer.' | |
| $cipherSuitesOrder = @( | |
| # TLS 1.3 cipher suites | |
| 'TLS_AES_256_GCM_SHA384', | |
| 'TLS_AES_128_GCM_SHA256', | |
| # Note: TLS_CHACHA20_POLY1305_SHA256 is supported but not enabled by default per Microsoft | |
| # TLS 1.2 cipher suites - ECDSA suites (prioritized for ECC certificates) | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', | |
| # TLS 1.2 cipher suites - RSA suites (most common) | |
| 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', | |
| # Note: DHE suites not included - disabled by default in Server 2022 23H2+ per Microsoft | |
| # CBC-mode suites for broader compatibility | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', | |
| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', | |
| # Note: Removed ECDHE CBC_SHA (SHA-1) cipher suites - only needed for TLS 1.0/1.1 which this script disables | |
| # RSA key exchange (no forward secrecy, but needed for some legacy scenarios) - SHA-256 only | |
| 'TLS_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_RSA_WITH_AES_128_GCM_SHA256', | |
| 'TLS_RSA_WITH_AES_256_CBC_SHA256', | |
| 'TLS_RSA_WITH_AES_128_CBC_SHA256' | |
| # Note: Removed RSA CBC_SHA (SHA-1) cipher suites - only needed for TLS 1.0/1.1 which this script disables | |
| ) | |
| } else { | |
| # Windows 10 (builds 10240-22000), Server 2016 (14393+), Server 2019 (17763+) | |
| Write-Host 'Use cipher suites order for Windows 10/Server 2016/Server 2019.' | |
| $cipherSuitesOrder = @( | |
| # TLS 1.2 cipher suites with perfect forward secrecy (ECDHE) | |
| # ECDSA suites prioritized per modern best practices | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256', | |
| 'TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384', | |
| 'TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256', | |
| 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384', | |
| 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256', | |
| # Note: Removed CBC_SHA (SHA-1) cipher suites - only needed for TLS 1.0/1.1 which this script disables | |
| # DHE for additional compatibility (enabled by default on these versions) | |
| 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256', | |
| # RSA key exchange (no forward secrecy) - SHA-256 only | |
| 'TLS_RSA_WITH_AES_256_GCM_SHA384', | |
| 'TLS_RSA_WITH_AES_128_GCM_SHA256', | |
| 'TLS_RSA_WITH_AES_256_CBC_SHA256', | |
| 'TLS_RSA_WITH_AES_128_CBC_SHA256' | |
| # Note: Removed RSA CBC_SHA (SHA-1) cipher suites - only needed for TLS 1.0/1.1 which this script disables | |
| ) | |
| } | |
| $cipherSuitesAsString = [string]::join(',', $cipherSuitesOrder) | |
| # One user reported this key does not exists on Windows 2012R2. Cannot repro myself on a brand new Windows 2012R2 core machine. Adding this just to be save. | |
| New-Item 'HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002' -ErrorAction SilentlyContinue | |
| New-ItemProperty -path 'HKLM:\SOFTWARE\Policies\Microsoft\Cryptography\Configuration\SSL\00010002' -name 'Functions' -value $cipherSuitesAsString -PropertyType 'String' -Force | Out-Null | |
| # Exchange Server TLS guidance Part 2: Enabling TLS 1.2 and Identifying Clients Not Using It | |
| # https://blogs.technet.microsoft.com/exchange/2018/04/02/exchange-server-tls-guidance-part-2-enabling-tls-1-2-and-identifying-clients-not-using-it/ | |
| # New IIS functionality to help identify weak TLS usage | |
| # https://cloudblogs.microsoft.com/microsoftsecure/2017/09/07/new-iis-functionality-to-help-identify-weak-tls-usage/ | |
| Write-Host 'Enable TLS 1.2 for .NET 3.5 and .NET 4.x' | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v2.0.50727" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v2.0.50727" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\.NETFramework\v4.0.30319" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| if (Test-Path 'HKLM:\SOFTWARE\Wow6432Node') { | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name 'SystemDefaultTlsVersions' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v4.0.30319" -name 'SchUseStrongCrypto' -value 1 -PropertyType 'DWord' -Force | Out-Null | |
| } | |
| # DefaultSecureProtocols Value Decimal value Protocol enabled | |
| # 0x00000008 8 Enable SSL 2.0 by default | |
| # 0x00000020 32 Enable SSL 3.0 by default | |
| # 0x00000080 128 Enable TLS 1.0 by default | |
| # 0x00000200 512 Enable TLS 1.1 by default | |
| # 0x00000800 2048 Enable TLS 1.2 by default | |
| # 0x00002000 8192 Enable TLS 1.3 by default | |
| $defaultSecureProtocols = @( | |
| '2048', # TLS 1.2 | |
| '8192' # TLS 1.3 | |
| ) | |
| $defaultSecureProtocolsSum = ($defaultSecureProtocols | Measure-Object -Sum).Sum | |
| # Update to enable TLS 1.2 as a default secure protocols in WinHTTP in Windows | |
| # https://support.microsoft.com/en-us/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in | |
| # Verify if hotfix KB3140245 is installed. | |
| $file_version_winhttp_dll = (Get-Item $env:windir\System32\winhttp.dll).VersionInfo | % {("{0}.{1}.{2}.{3}" -f $_.ProductMajorPart,$_.ProductMinorPart,$_.ProductBuildPart,$_.ProductPrivatePart)} | |
| $file_version_webio_dll = (Get-Item $env:windir\System32\Webio.dll).VersionInfo | % {("{0}.{1}.{2}.{3}" -f $_.ProductMajorPart,$_.ProductMinorPart,$_.ProductBuildPart,$_.ProductPrivatePart)} | |
| if ([System.Version]$file_version_winhttp_dll -lt [System.Version]"6.1.7601.23375" -or [System.Version]$file_version_webio_dll -lt [System.Version]"6.1.7601.23375") { | |
| Write-Host 'WinHTTP: Cannot enable TLS 1.2. Please see https://support.microsoft.com/en-us/help/3140245/update-to-enable-tls-1-1-and-tls-1-2-as-a-default-secure-protocols-in for system requirements.' | |
| } else { | |
| Write-Host 'WinHTTP: Minimum system requirements are met.' | |
| Write-Host 'WinHTTP: Activate TLS 1.2 and TLS 1.3.' | |
| New-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -name 'DefaultSecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null | |
| if (Test-Path 'HKLM:\SOFTWARE\Wow6432Node') { | |
| # WinHttp key seems missing in Windows 2019 for unknown reasons. | |
| New-Item 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -ErrorAction SilentlyContinue | Out-Null | |
| New-ItemProperty -path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Internet Settings\WinHttp' -name 'DefaultSecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null | |
| } | |
| } | |
| Write-Host 'Windows Internet Explorer: Activate TLS 1.2 and TLS 1.3.' | |
| New-ItemProperty -path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' -name 'SecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null | |
| New-ItemProperty -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings' -name 'SecureProtocols' -value $defaultSecureProtocolsSum -PropertyType 'DWord' -Force | Out-Null | |
| Write-Host '--------------------------------------------------------------------------------' | |
| Write-Host 'NOTE: After the system has been rebooted you can verify your server' | |
| Write-Host ' configuration at https://www.ssllabs.com/ssltest/' | |
| Write-Host "--------------------------------------------------------------------------------`n" | |
| Write-Host -ForegroundColor Red 'A computer restart is required to apply settings. Restart computer now?' | |
| Restart-Computer -Force -Confirm | |
| # History | |
| # 30.10.2025: Released v4.0.0 by Pax | |
| # TLS 1.3 Support: | |
| # - Added TLS 1.3 protocol support for Windows 11, Server 2022, and Server 2025 | |
| # - Implemented accurate OS detection based on build numbers per Microsoft documentation: | |
| # https://learn.microsoft.com/en-us/windows/win32/secauthn/protocols-in-tls-ssl--schannel-ssp- | |
| # - Added TLS 1.3 cipher suites: TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256 | |
| # - Updated DefaultSecureProtocols to include TLS 1.3 (0x00002000/8192) | |
| # - Note: TLS_CHACHA20_POLY1305_SHA256 not included (supported but not enabled by default per Microsoft) | |
| # | |
| # Cipher Suite Modernization: | |
| # - Updated cipher suite ordering per official Microsoft documentation: | |
| # * Server 2022/2025/Win 11: https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2022 | |
| # * Server 2025: https://learn.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-server-2025 | |
| # - Prioritized ECDSA cipher suites before RSA suites (modern best practice for ECC certificates) | |
| # - Removed DHE suites from Server 2022/2025 configuration (disabled by default in 23H2+) | |
| # - Created three-tier cipher configuration optimized per Windows version: | |
| # * Windows 2008 R2 and earlier (SHA-256 only) | |
| # * Windows 10/Server 2016/2019 (TLS 1.2 with DHE support) | |
| # * Windows 11/Server 2022/2025 (TLS 1.3 + modern TLS 1.2) | |
| # | |
| # SHA-1 Deprecation (Critical Security): | |
| # - Disabled SHA-1 hash algorithm globally (deprecated due to collision attacks) | |
| # - Removed all SHA-1-based cipher suites from ALL Windows configurations: | |
| # * Removed TLS_ECDHE_*_WITH_AES_*_CBC_SHA (uses SHA-1 for HMAC) | |
| # * Removed TLS_RSA_WITH_AES_*_CBC_SHA (uses SHA-1 for HMAC) | |
| # - Aligns with Microsoft SHA-1 deprecation policy: | |
| # https://learn.microsoft.com/en-us/lifecycle/announcements/sha-1-signed-content-retired | |
| # | |
| # 20.06.2022: Released v3.0.2, Added TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 for Azure Devops compatibility | |
| # 10.03.2019: Released v3.0.1, v2.0.1, v1.9.2. Added Windows 2019 support. No security changes. | |
| # 17.11.2018: Released v3.0.0. Support TLS 1.2 only. Hardended Windows 2016 server configuration so clients can use the enhanced security. Windows 2012R2 or older servers cannot hardened without getting B penalty from SSLLabs. You may better upgrade your Windows servers! | |
| # 21.09.2018: Released v2.0.0. Jump from 1.12 to 2.0 to be able to maintain two compatibility branches. Changes: Configure protocols for Internet Explorer. Added SchUseStrongCrypto registry key to increase security for older .NET versions. | |
| # 21.09.2018: Released v1.9.1. Parallel maintained branch as there is still a need for it. Changes: Configure protocols for Internet Explorer. Added SchUseStrongCrypto registry key to increase security for older .NET versions., Fixed version compare on winhttp.dll and webio.dll. No security or other changes. | |
| # 25.08.2018: Released v1.12. Fixed version compare on winhttp.dll and webio.dll. No security or other changes. | |
| # 23.07.2018: Released v1.11. Removed 3DES as it is marked weak. Minimum cipher strenght increased to 128bit as requested by TÜV Süd safer shopping certification. | |
| # 10.04.2018: Released v1.10. Implemented a more secure version for online shops that are PCI DSS certified. In order to meet the PCI Data Security Standard (PCI DSS) for safeguarding payment data there is an upcomming deadline on 30. June 2018 that require you to disable TLS 1.0. | |
| # 10.04.2018: Released v1.9. Enabled TLS 1.1 and TLS 1.2 for WinHttp (client connections). Hardened Diffie-Hellman Key Exchange and .NET client connections. | |
| # 28.08.2017: Released v1.8. Windows 2016 powershell version 5.1.14393.1532 (and maybe others) require 'else' and 'elseif' statements in the same line after to the closing 'if' curly quote. Windows 2016 RTM has worked like a charm. WTF!? Very bad code style... I really hate it! | |
| # 26.09.2016: Released v1.7. Windows Version compare failed and Get-CimInstance requires Windows 2012 or later, but the script supports Windows 2008R2 and later. | |
| # 20.09.2016: Released v1.6 with OS detection. Used incorrect cipher suites order in v1.5. | |
| # 19.09.2016: Released v1.5 with enabled ECDH and more secure hash functions and reorderd cipher list. Added Client setting for all ciphers. An extra Windows 2016 version has added with renamed ciphers. Use this Windows 2016 version only for Windows 2016 and later. Fixed incorrect "Triple DES 168/168" name. | |
| # 24.08.2016: Reset to defaults script added. Just in case someone looking for it, but this is not needed except testing. | |
| # 09.12.2014: Disabled and removed RC4 to get a SSLLabs rating of A. For backward compatibility Windows XP with Internet Explorer 8 machines will fallback to TLS_RSA_WITH_3DES_EDE_CBC_SHA. TLS_RSA_WITH_3DES_EDE_CBC_SHA is only there to support the very last Windows XP machines with IE8. If you do not like to support IE8 any longer you may also remove this. | |
| # 07.12.2014: Microsoft seems to have found connection issues with the 4 new ciphers 'TLS_DHE_RSA_WITH_AES_256_GCM_SHA384', 'TLS_DHE_RSA_WITH_AES_128_GCM_SHA256', 'TLS_RSA_WITH_AES_256_GCM_SHA384', 'TLS_RSA_WITH_AES_128_GCM_SHA256'. They are disabled as before for now. See MS14-066: Vulnerability in SChannel could allow remote code execution: November 11, 2014 for more information, please. | |
| # 07.11.2014: Disabled MD5 chipher as this is not used. | |
| # 04.11.2014: Re-factored code style and output. | |
| # 16.10.2014: Disabled SSLv3 by default to protect against Poodle attacks. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment