diff --git a/AGENTS.md b/AGENTS.md index d54ded13..9cc2594f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -190,3 +190,4 @@ When the user corrects an agent approach, add or tighten one concrete rule here - Log install/uninstall package names and package-manager IDs before queuing background runspace work; do not rely on runspace host output for the package identity. - For Win11 Creator, start each new ISO modification in a fresh `WinUtil_Win11ISO_*` temp directory; existing-work detection is only for resuming/exporting already modified media. - For Script Analyzer cleanup, fix actionable source warnings first and do not globally suppress accepted convention warnings such as plural names, `ShouldProcess` on UI helpers, `$global:sync`, or compile-time cross-file false positives. +- For DNS DHCP reset, keep the cmdlet reset and explicitly set IPv4 and IPv6 DNS source to DHCP. diff --git a/functions/private/Set-WinUtilDNS.ps1 b/functions/private/Set-WinUtilDNS.ps1 index f96a5682..f12da27d 100644 --- a/functions/private/Set-WinUtilDNS.ps1 +++ b/functions/private/Set-WinUtilDNS.ps1 @@ -12,25 +12,38 @@ function Set-WinUtilDNS { #> param($DNSProvider) + if($DNSProvider -eq "Default") { Write-WinUtilLog -Component "DNS" -Message "DNS provider is Default; no DNS changes applied." return } + try { $Adapters = Get-NetAdapter | Where-Object {$_.Status -eq "Up"} Write-Host "Ensuring DNS is set to $DNSProvider on the following interfaces:" Write-Host $($Adapters | Out-String) Write-WinUtilLog -Component "DNS" -Message "Setting DNS provider to $DNSProvider for $(@($Adapters).Count) active adapter(s)." + if($DNSProvider -ne "DHCP") { + $dns = $sync.configs.dns.$DNSProvider + if($null -eq $dns) { + Write-Warning "DNS provider $DNSProvider was not found in configuration." + Write-WinUtilLog -Level "ERROR" -Component "DNS" -Message "DNS provider $DNSProvider was not found in configuration." + return + } + } + Foreach ($Adapter in $Adapters) { if($DNSProvider -eq "DHCP") { Write-WinUtilLog -Component "DNS" -Message "Resetting DNS to DHCP on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex))." Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ResetServerAddresses + netsh interface ip set dnsservers name="$($Adapter.Name)" source=dhcp + netsh interface ipv6 set dnsservers name="$($Adapter.Name)" source=dhcp } else { - Write-WinUtilLog -Component "DNS" -Message "Setting IPv4 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($sync.configs.dns.$DNSProvider.Primary), $($sync.configs.dns.$DNSProvider.Secondary)." - Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ("$($sync.configs.dns.$DNSProvider.Primary)", "$($sync.configs.dns.$DNSProvider.Secondary)") - Write-WinUtilLog -Component "DNS" -Message "Setting IPv6 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($sync.configs.dns.$DNSProvider.Primary6), $($sync.configs.dns.$DNSProvider.Secondary6)." - Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ("$($sync.configs.dns.$DNSProvider.Primary6)", "$($sync.configs.dns.$DNSProvider.Secondary6)") + Write-WinUtilLog -Component "DNS" -Message "Setting IPv4 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($dns.Primary), $($dns.Secondary)." + Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ($dns.Primary, $dns.Secondary) + Write-WinUtilLog -Component "DNS" -Message "Setting IPv6 DNS on adapter $($Adapter.Name) (ifIndex: $($Adapter.ifIndex)) to $($dns.Primary6), $($dns.Secondary6)." + Set-DnsClientServerAddress -InterfaceIndex $Adapter.ifIndex -ServerAddresses ($dns.Primary6, $dns.Secondary6) } } Write-WinUtilLog -Component "DNS" -Message "DNS provider change completed: $DNSProvider" diff --git a/functions/public/Invoke-WPFtweaksbutton.ps1 b/functions/public/Invoke-WPFtweaksbutton.ps1 index 9f484210..f2edb04a 100644 --- a/functions/public/Invoke-WPFtweaksbutton.ps1 +++ b/functions/public/Invoke-WPFtweaksbutton.ps1 @@ -70,7 +70,9 @@ function Invoke-WPFtweaksbutton { } } - Set-WinUtilDNS -DNSProvider $dnsProvider + if ($dnsProvider -ne "Default") { + Set-WinUtilDNS -DNSProvider $dnsProvider + } for ($i = 0; $i -lt $tweaks.Count; $i++) { Set-WinUtilProgressBar -Label "Applying $($tweaks[$i])" -Percent ($completedSteps / $totalSteps * 100) diff --git a/pester/dns.Tests.ps1 b/pester/dns.Tests.ps1 new file mode 100644 index 00000000..ff59e6d9 --- /dev/null +++ b/pester/dns.Tests.ps1 @@ -0,0 +1,118 @@ +#=========================================================================== +# Tests - DNS +#=========================================================================== + +BeforeAll { + $script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path + + function Get-NetAdapter { } + function Set-DnsClientServerAddress { + param( + $InterfaceIndex, + $ServerAddresses, + [switch]$ResetServerAddresses + ) + } + function netsh { + param( + [Parameter(ValueFromRemainingArguments = $true)] + [string[]]$Arguments + ) + } + function Write-WinUtilLog { + param($Message, $Level, $Component) + } + + . (Join-Path $script:repoRoot "functions\private\Set-WinUtilDNS.ps1") +} + +Describe "Set-WinUtilDNS" { + BeforeEach { + $script:sync = [Hashtable]::Synchronized(@{ + configs = @{ + dns = @{ + Cloudflare = [pscustomobject]@{ + Primary = "1.1.1.1" + Secondary = "1.0.0.1" + Primary6 = "2606:4700:4700::1111" + Secondary6 = "2606:4700:4700::1001" + } + } + } + }) + + Mock Get-NetAdapter { + [pscustomobject]@{ + Name = "Ethernet" + Status = "Up" + ifIndex = 7 + } + } + Mock Set-DnsClientServerAddress { } + Mock netsh { } + Mock Write-WinUtilLog { } + Mock Write-Warning { } + Mock Write-Host { } + } + + AfterEach { + Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue + } + + It "sets IPv4 and IPv6 DNS server addresses separately" { + Set-WinUtilDNS -DNSProvider "Cloudflare" + + Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter { + $InterfaceIndex -eq 7 -and + $ServerAddresses.Count -eq 2 -and + $ServerAddresses[0] -eq "1.1.1.1" -and + $ServerAddresses[1] -eq "1.0.0.1" + } + Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter { + $InterfaceIndex -eq 7 -and + $ServerAddresses.Count -eq 2 -and + $ServerAddresses[0] -eq "2606:4700:4700::1111" -and + $ServerAddresses[1] -eq "2606:4700:4700::1001" + } + Should -Invoke -CommandName Set-DnsClientServerAddress -Times 0 -Exactly -ParameterFilter { + $ServerAddresses.Count -eq 4 + } + } + + It "resets DNS to DHCP for IPv4 and IPv6" { + Set-WinUtilDNS -DNSProvider "DHCP" + + Should -Invoke -CommandName Set-DnsClientServerAddress -Times 1 -Exactly -ParameterFilter { + $InterfaceIndex -eq 7 -and + $ResetServerAddresses -eq $true + } + Should -Invoke -CommandName netsh -Times 1 -Exactly -ParameterFilter { + $Arguments[0] -eq "interface" -and + $Arguments[1] -eq "ip" -and + $Arguments[2] -eq "set" -and + $Arguments[3] -eq "dnsservers" -and + $Arguments[4] -eq "name=Ethernet" -and + $Arguments[5] -eq "source=dhcp" + } + Should -Invoke -CommandName netsh -Times 1 -Exactly -ParameterFilter { + $Arguments[0] -eq "interface" -and + $Arguments[1] -eq "ipv6" -and + $Arguments[2] -eq "set" -and + $Arguments[3] -eq "dnsservers" -and + $Arguments[4] -eq "name=Ethernet" -and + $Arguments[5] -eq "source=dhcp" + } + } + + It "catches DNS setter failures so the tweak runspace can continue" { + Mock Set-DnsClientServerAddress { throw "DNS failed" } + + { Set-WinUtilDNS -DNSProvider "Cloudflare" } | Should -Not -Throw + + Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter { + $Level -eq "ERROR" -and + $Component -eq "DNS" -and + $Message -like "Unable to set DNS provider Cloudflare*" + } + } +}