Bake 125 DoH servers into Windows before it even installs.
Injects all 125 DNS-over-HTTPS Well-Known Server entries directly into a Windows install.wim or install.esd image — offline, before installation. When Windows is installed from the modified image, every provider is pre-registered from first boot. No post-install tool needed.
Windows 10 and 11 have a built-in DNS-over-HTTPS feature accessible via Settings → Network & Internet → DNS Settings. When you set a DNS server IP, Windows checks its internal DohWellKnownServers registry list to see if that IP has a known DoH endpoint — if it does, it auto-fills the HTTPS template for you.
The problem: Microsoft's built-in list ships with only 3 providers — Cloudflare, Google, and Quad9 — unchanged since the feature was first introduced in Windows 10 Insider Build 20185 (August 2020). The official Microsoft documentation (last updated December 2023) still reflects only these same 3 providers. All other DNS providers — including Mullvad, AdGuard, Control D, OpenDNS, DNS4EU, Clean Browsing, LibreDNS, Uncensored DNS, and more — are not on the list, so Windows cannot auto-template them.
This script solves that by injecting all 125 provider entries directly into the WIM image before Windows is installed, using two registry paths:
-
HKLM\SYSTEM\ControlSet001\Services\Dnscache\Parameters\DohWellKnownServersRegisters each DNS IP with its DoHTemplateURL. This is the key path Windows reads to auto-fill the endpoint. -
HKLM\SYSTEM\ControlSet001\Services\Dnscache\InterfaceSpecificParameters\GlobalDohIPSetsDohTemplateandDohFlagsper IP. UsingGlobalDohIPas the key name circumvents the need to target individual network adapter GUIDs, which change per machine and would make offline injection impractical.
Note: The script targets
ControlSet001rather thanCurrentControlSet. In an offline loaded hive,CurrentControlSetis an unresolved symlink — writing to it silently places keys at an invalid location, which causes0x67 CONFIG_INITIALIZATION_FAILEDon first boot.ControlSet001is the correct path for offline hive operations. On a running Windows system,CurrentControlSetmaps toControlSet001, so all injected keys are read correctly after installation.
The script mounts the WIM via DISM, loads the offline SYSTEM hive into a temporary registry alias, writes all entries into ControlSet001, flushes all .NET handles, unloads the hive, verifies the hive is fully released, and then commits the image. Changes are baked into the WIM — Windows Setup carries them into every installation from that image.
- Windows 10 or Windows 11
- DISM — built into Windows, no install needed
- PowerShell 5.1 or later — built into Windows
- Run as Administrator
- A Windows ISO (downloaded from Microsoft)
- Rufus for creating the USB installer
Download a genuine Windows 10 or 11 ISO directly from Microsoft:
Save the ISO to your local PC. Do not mount it — it is only needed for the next step.
Recommended: Use git clone — this is the preferred method. It gives you the latest version of the script, avoids Windows script-blocking issues with browser-downloaded files, and makes updating a single command in Step 7.
git clone https://github.com/1LUC1D4710N/doh-windows-installer-wim.git C:\Tools\doh-wimDon't have Git? Download Git for Windows — it takes two minutes to install and is worth having.
Alternative (no Git): Click Install-DoH-WIM.ps1 in the file list above → click the download button → save to C:\Tools\doh-wim\. Note that files downloaded through a browser may be flagged by Windows and require extra steps before PowerShell will run them. Using git clone avoids this entirely.
Download Rufus and use it to create a bootable Windows USB installer:
- Run Rufus
- Select your USB drive
- Click SELECT and choose your Windows ISO
- Click START and follow the prompts
- Wait for Rufus to finish writing the USB
The USB will now contain sources\install.wim — this is the file you will replace in the next steps.
The install.wim on the USB installer created in Step 3 is read-only and cannot be modified in place. Copy it from the USB to a local working folder on your PC so DISM can mount and modify it.
New-Item -ItemType Directory -Path "C:\Temp" -Force
Copy-Item "X:\sources\install.wim" "C:\Temp\install.wim"Replace X: with your USB drive letter. To check your USB drive letter, open File Explorer — it is shown next to your USB drive name.
Note: Copying 6+ GB takes a few minutes. Wait for the prompt to return before continuing.
Files copied from a USB carry the read-only attribute. Remove it before running the script:
attrib -R "C:\Temp\install.wim"A single WIM file contains all Windows editions, each with its own index number. To see what is inside:
dism /Get-WimInfo /WimFile:"C:\Temp\install.wim"Example output:
Index : 1 → Windows 11 Home
Index : 2 → Windows 11 Home N
Index : 3 → Windows 11 Pro
...
Using -AllIndexes processes all editions automatically, so you do not need to note individual numbers unless targeting a specific edition.
Before running, make sure you are using the latest version of the script. If you cloned the repository, pull the latest changes:
git -C C:\Tools\doh-wim pullIf you downloaded Install-DoH-WIM.ps1 manually, re-download it from the repo to ensure you have the current version before continuing.
Open PowerShell as Administrator (right-click → Run as Administrator), then allow the script to run (required once — Windows blocks unsigned scripts by default):
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserThe commands below use the full path to the script so they work from any folder — you do not need to navigate into the script directory first.
Process all editions in one run:
C:\Tools\doh-wim\Install-DoH-WIM.ps1 -WimPath "C:\Temp\install.wim" -AllIndexesOr target a single edition by index number (replace 6 with your chosen index from Step 6):
C:\Tools\doh-wim\Install-DoH-WIM.ps1 -WimPath "C:\Temp\install.wim" -WimIndex 6The script will mount, inject, and commit each index one by one. A summary is printed at the end showing which indexes passed or failed. Expect 5–15 minutes for all 11 editions depending on drive speed.
After injection is complete, restore the read-only attribute before copying the file back to the USB:
attrib +R "C:\Temp\install.wim"This mirrors the original state of the file on the USB installer.
Once the script completes successfully, replace the original install.wim on your USB with the modified one:
Copy-Item "C:\Temp\install.wim" "X:\sources\install.wim"Replace X: with your USB drive letter.
Boot from the USB and install Windows as normal. All 125 DoH providers are pre-registered from the moment installation completes — no post-install tools required.
After first boot:
- Open Settings (Win+I)
- Go to Network & Internet → Advanced network settings → DNS Settings
- Click Edit next to DNS servers
- Select Manual
- Toggle IPv4 to On and IPv6 to On
- Under DNS over HTTPS, select On (automatic template)
- Type your preferred provider's IPv4 address
- Type your preferred provider's IPv6 address
- Click Save — Windows auto-fills the DoH endpoint
Your DNS is now encrypted from the first configuration.
Some ISOs contain install.esd instead of install.wim. Convert it to WIM before running the script:
dism /Export-Image /SourceImageFile:"C:\Temp\install.esd" /SourceIndex:1 /DestinationImageFile:"C:\Temp\install.wim" /Compress:max /CheckIntegrityThen run the script against the exported install.wim.
| Provider | Type | IPv4 | IPv6 | Best For |
|---|---|---|---|---|
| Cloudflare | Tiered | 1.1.1.1 | 2606:4700:4700::1111 | Speed + Reliability |
| Control D | Multi-filter | 76.76.2.x | 2606:1a40::x | Granular Control |
| DNS4EU | Multi-filter | 86.54.11.x | 2a13:1001::... | European Privacy |
| Quad9 | Security | 9.9.9.9 | 2620:fe::9 | Non-profit Security |
| Standard | 8.8.8.8 | 2001:4860:4860::8888 | Performance | |
| Mullvad | Privacy-first | 194.242.2.2 | 2a07:e340::2 | Privacy + Adblock |
| AdGuard | Multi-filter | 94.140.14.14 | 2a10:50c0::ad1:ff | All-in-one Protection |
| OpenDNS | Enterprise | 208.67.222.222 | 2620:119:35::35 | Business Use |
| Clean Browsing | Family | 185.228.168.168 | 2a0d:2a00:1:: | Family Safety |
| LibreDNS | Minimal | 116.202.176.26 | 2a01:4f8:1c0c:8274::1 | Lightweight |
| Uncensored DNS | No-filter | 91.239.100.100 | 2001:67c:28a4:: | Unrestricted |
125 configurations total — IPv4 and IPv6 for all providers.
→ See full DNS Providers Reference for all 125 IPs and DoH endpoints.
Script will not run / blocked by Windows Run this once in an Administrator PowerShell window, then retry:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUserDISM mount fails with permissions error (0xc1510111) The WIM file is read-only. Strip the attribute before running the script:
attrib -R "C:\Temp\install.wim"DISM mount fails with dirty mount error A previous mount was not cleaned up. Run:
dism /Cleanup-Wimreg unload fails with Access Denied
Close any open registry editor windows and retry. The script includes [gc]::Collect(), [gc]::WaitForPendingFinalizers(), and a 2-second delay to fully release all handles before unloading.
ESD export fails Try a lower compression level:
dism /Export-Image /SourceImageFile:install.esd /SourceIndex:1 /DestinationImageFile:install.wim /Compress:fastSystem boots to 0x67 (CONFIG_INITIALIZATION_FAILED) after injection
The registry configuration failed on boot. This was caused by writing DoH keys to CurrentControlSet in the offline hive — CurrentControlSet is a symlink that does not resolve in an offline loaded hive, so the keys were written to an invalid location. The script has been corrected to use ControlSet001 instead. If you are seeing this error from a previous version, re-run the script against a fresh copy of install.wim.
If the issue persists after re-running, use these diagnostics:
| Check | Command |
|---|---|
| View DISM log | notepad C:\Windows\Logs\DISM\dism.log |
| List stale mount points | dism /Get-MountedWimInfo |
| Clean up broken mounts | dism /Cleanup-Wim |
| Discard and unmount | dism /Unmount-Image /MountDir:C:\Mount /Discard |
| Check WIM indexes | dism /Get-WimInfo /WimFile:C:\Temp\install.wim |
After installing Windows from the modified image, run these checks in PowerShell to confirm all 125 entries were baked in correctly and survived the full Windows Setup process.
$keys = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DohWellKnownServers"
Write-Host "DohWellKnownServers entries: $($keys.Count)"Expected output: DohWellKnownServers entries: 125
$keys = Get-ChildItem "HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\InterfaceSpecificParameters\GlobalDohIP"
Write-Host "GlobalDohIP entries: $($keys.Count)"Expected output: GlobalDohIP entries: 125
Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DohWellKnownServers\9.9.9.9"
Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\InterfaceSpecificParameters\GlobalDohIP\9.9.9.9"Expected: Template shows https://dns.quad9.net/dns-query, DohTemplate matches, and DohFlags is present.
- Open Settings → Network & Internet → Advanced network settings → DNS Settings
- Click Edit next to DNS servers
- Select Manual and toggle IPv4 on
- Type any provider IP from the list — for example
9.9.9.9,94.140.14.14, or194.242.2.2 - "On (automatic template)" should appear and auto-fill the DoH URL without you typing it
If all four tests pass — the image was correctly modified and Windows was born with all 125 DoH providers registered. ✅
MIT License — No email. No tracking. No accounts.