Main/Set-BuiltInWinSecureDNS.psm1
Function Set-BuiltInWinSecureDNS { [Alias('Set-DOH')] [CmdletBinding()] [OutputType([System.String], [Microsoft.Management.Infrastructure.CimInstance])] param ( [ValidateSet('Cloudflare', 'CloudFlareFamily', 'CloudFlareAntiMalware', 'Quad9' , 'Quad9MalwareBlocking', 'Google', ErrorMessage = 'The selected DNS over HTTPS provider is not supported by Windows. Please select a different provider or use the Set-CustomWinSecureDNS cmdlet.')] [Parameter(Mandatory = $false)][System.String]$DoHProvider = 'Cloudflare' ) begin { # Detecting if Verbose switch is used [System.Boolean]$Verbose = $PSBoundParameters.Verbose.IsPresent ? $true : $false # Importing the $PSDefaultParameterValues to the current session, prior to everything else . "$WinSecureDNSMgrModuleRootPath\MainExt\PSDefaultParameterValues.ps1" # Importing the required sub-modules Import-Module -Name "$WinSecureDNSMgrModuleRootPath\Shared\Get-ActiveNetworkAdapterWinSecureDNS.psm1" -Force Import-Module -Name "$WinSecureDNSMgrModuleRootPath\Shared\Get-ManualNetworkAdapterWinSecureDNS.psm1" -Force Import-Module -Name "$WinSecureDNSMgrModuleRootPath\Shared\Select-Option.psm1" -Force # This service shouldn't be disabled # https://github.com/HotCakeX/WinSecureDNSMgr/issues/7 if (!((Get-Service -Name 'Dnscache').StartType -ne 'Disabled')) { throw 'The DNS Client service status is disabled. Please start the service and try again.' } # Get the DoH domain from the hashtable - Since all of the DoH domains are identical for the same provider, only getting the first item in the array [System.String]$DetectedDoHTemplate = ($BuiltInDoHTemplatesReference.GetEnumerator() | Where-Object { $_.Key -eq $DoHProvider }).Value.Values.Values[0] # Automatically detect the correct network adapter [Microsoft.Management.Infrastructure.CimInstance]$ActiveNetworkInterface = Get-ActiveNetworkAdapterWinSecureDNS # Display the detected network adapter and ask the user if it's correct $ActiveNetworkInterface # Loop until the user confirms the detected adapter is the correct one, Selects the correct network adapter or Cancels switch (Select-Option -Options 'Yes', 'No - Select Manually', 'Cancel' -Message "`nIs the detected network adapter correct ?") { 'Yes' { $ActiveNetworkInterface = $ActiveNetworkInterface } 'No - Select Manually' { [Microsoft.Management.Infrastructure.CimInstance]$ActiveNetworkInterface = Get-ManualNetworkAdapterWinSecureDNS } 'Cancel' { Write-Host -Object 'Exiting...' -ForegroundColor Yellow # Set the $shouldExit variable to $True indicating the subsequent blocks to exit the function [System.Boolean]$ShouldExit = $True return } } # Set the $shouldExit variable to $True and exit the function in the subsequent blocks if no network adapter is selected if (!$ActiveNetworkInterface) { $ShouldExit = $True return } } process { # if the user selected Cancel, do not proceed with the process block if ($ShouldExit) { Return } # reset the network adapter's DNS servers back to default to take care of any IPv6 strays Set-DnsClientServerAddress -InterfaceIndex $ActiveNetworkInterface.ifIndex -ResetServerAddresses # delete all other previous DoH settings for ALL Interface - Windows behavior in settings when changing DoH settings is to delete all DoH settings for the interface we are modifying # but we need to delete all DoH settings for ALL interfaces in here because every time we virtualize a network adapter with external switch of Hyper-V, # Hyper-V assigns a new GUID to it, so it's better not to leave any leftover in the registry and clean up after ourselves $null = Remove-Item -Path 'Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Dnscache\InterfaceSpecificParameters\*' -Recurse # Define empty arrays to store IPv4 and IPv6 addresses [System.String[]]$DoHIPs = @() [System.String[]]$IPV4s = @() [System.String[]]$IPV6s = @() [System.Boolean]$IsExtraProvider = $false # If using a provider that is not available by default in Windows then get its IP addresses from the JSON file if ($DoHProvider -in 'CloudFlareFamily', 'CloudFlareAntiMalware', 'Quad9MalwareBlocking') { $IsExtraProvider = $true [System.String[]]$DoHIPs = foreach ($Item in $BuiltInDoHTemplatesReference.GetEnumerator()) { if ($Item.Key -eq $DoHProvider) { $Item.Value.Values.Keys } } # Detect version of each IP address and store them in the appropriate array foreach ($IP in $DoHIPs) { if (([System.Net.IPAddress]$IP).AddressFamily -eq 'InterNetwork') { $IPV4s += $IP } elseif (([System.Net.IPAddress]$IP).AddressFamily -eq 'InterNetworkV6') { $IPV6s += $IP } } # check if there is any IP address already associated with $DetectedDoHTemplate and if so, delete them foreach ($Item in Get-DnsClientDohServerAddress) { if ($Item.dohTemplate -eq $DetectedDoHTemplate) { foreach ($OldIP in $Item.ServerAddress) { Remove-DnsClientDohServerAddress -ServerAddress $OldIP } } } Write-Verbose -Message 'Checking if the IP addresses of the currently selected DoH domain already exist and then deleting them' foreach ($Item in Get-DnsClientDohServerAddress) { if ($Item.ServerAddress -in $DoHIPs) { Remove-DnsClientDohServerAddress -ServerAddress $Item.ServerAddress } } } else { # Get the IP addresses associated with the built-in DOH servers [System.String[]]$DoHIPs = foreach ($Item in Get-DnsClientDohServerAddress) { if ($Item.DohTemplate -eq $DetectedDoHTemplate) { $Item.ServerAddress } } # Detect version of each IP address and store them in the appropriate array foreach ($IP in $DoHIPs) { if (([System.Net.IPAddress]$IP).AddressFamily -eq 'InterNetwork') { $IPV4s += $IP } elseif (([System.Net.IPAddress]$IP).AddressFamily -eq 'InterNetworkV6') { $IPV6s += $IP } } } foreach ($IPV4 in $IPV4s) { # defining registry path for DoH settings of the $ActiveNetworkInterface based on its GUID for IPv4 [System.String]$PathV4 = "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Dnscache\InterfaceSpecificParameters\$($ActiveNetworkInterface.InterfaceGuid)\DohInterfaceSettings\Doh\$IPV4" # add DoH settings for the specified Network adapter based on its GUID in registry # value 1 for DohFlags key means use automatic template for DoH, 2 means manual template, since we add our template to Windows, it's predefined so we use value 1 $null = New-Item -Path $PathV4 -Force $null = New-ItemProperty -Path $PathV4 -Name 'DohFlags' -Value 1 -PropertyType 'Qword' -Force if (!$IsExtraProvider) { Set-DnsClientDohServerAddress -ServerAddress $IPV4 -DohTemplate $DetectedDoHTemplate -AllowFallbackToUdp $False -AutoUpgrade $True } else { Write-Verbose -Message 'Associating the new IPv4s with the selected DoH template in Windows DoH template predefined list' $null = Add-DnsClientDohServerAddress -ServerAddress $IPV4 -DohTemplate $DetectedDoHTemplate -AllowFallbackToUdp $False -AutoUpgrade $True } } foreach ($IPV6 in $IPV6s) { # defining registry path for DoH settings of the $ActiveNetworkInterface based on its GUID for IPv6 [System.String]$PathV6 = "Registry::HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Dnscache\InterfaceSpecificParameters\$($ActiveNetworkInterface.InterfaceGuid)\DohInterfaceSettings\Doh6\$IPV6" # add DoH settings for the specified Network adapter based on its GUID in registry # value 1 for DohFlags key means use automatic template for DoH, 2 means manual template, since we already added our template to Windows, it's considered predefined, so we use value 1 $null = New-Item -Path $PathV6 -Force $null = New-ItemProperty -Path $PathV6 -Name 'DohFlags' -Value 1 -PropertyType 'Qword' -Force if (!$IsExtraProvider) { Set-DnsClientDohServerAddress -ServerAddress $IPV6 -DohTemplate $DetectedDoHTemplate -AllowFallbackToUdp $False -AutoUpgrade $True } else { Write-Verbose -Message 'Associating the new IPv4s with the selected DoH template in Windows DoH template predefined list' $null = Add-DnsClientDohServerAddress -ServerAddress $IPV6 -DohTemplate $DetectedDoHTemplate -AllowFallbackToUdp $False -AutoUpgrade $True } } # this is responsible for making the changes in Windows settings UI > Network and internet > $ActiveNetworkInterface.Name Set-DnsClientServerAddress -ServerAddresses $DoHIPs -InterfaceIndex $ActiveNetworkInterface.ifIndex } End { # if the user selected Cancel, do not proceed with the end block if ($ShouldExit) { Return } Write-Verbose -Message 'Clearing the DNS client cache' Clear-DnsClientCache Write-Host -Object "DNS over HTTPS (DoH) is now configured for $($ActiveNetworkInterface.Name) using $DoHProvider provider." -ForegroundColor Green # Define the name and path of the task [System.String]$TaskName = 'Dynamic DoH Server IP check' [System.String]$TaskPath = '\DDoH\' # Try to get the Dynamic DoH task and delete it if it exists if (Get-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -ErrorAction SilentlyContinue) { Unregister-ScheduledTask -TaskName $TaskName -TaskPath $TaskPath -Confirm:$false } } <# .SYNOPSIS Easily and quickly configure DNS over HTTPS (DoH) in Windows .LINK https://github.com/HotCakeX/WinSecureDNSMgr .DESCRIPTION Easily and quickly configure DNS over HTTPS (DoH) in Windows .PARAMETER DoHProvider The name of the 3 built-in DNS over HTTPS providers: Cloudflare, Google and Quad9 If no value is provided, the default provider is Cloudflare .EXAMPLE Set-BuiltInWinSecureDNS -DoHProvider Cloudflare Set-DOH -DoHProvider Cloudflare .PARAMETER Verbose Switch to enable verbose output .INPUTS System.String .OUTPUTS System.String Microsoft.Management.Infrastructure.CimInstance #> } |