# Reverses install.ps1 -- run from an ELEVATED PowerShell. $ErrorActionPreference = "Stop" $stateFile = Join-Path $PSScriptRoot "install-state.json" # install.ps1 adds one rule per activated TLD, each commented "BNS . resolver". # Match them all -- an exact match on ".bch" used to leave every other TLD's rule # behind, still pointing at the daemon we are removing. Get-DnsClientNrptRule | Where-Object { $_.Comment -like "BNS *resolver" } | ForEach-Object { Remove-DnsClientNrptRule -Name $_.Name -Force Write-Host "[ok] NRPT rule removed ($($_.Namespace -join ', '))" } if (Test-Path $stateFile) { $state = Get-Content $stateFile | ConvertFrom-Json foreach ($a in $state.adapters) { # Never "restore" DNS to 127.0.0.1 (the daemon we're removing) -- that leaves the # machine with no working resolver. Drop loopback; if nothing real remains, or the # install marked this adapter, hand DNS back to DHCP (automatic). $servers = @($a.servers | Where-Object { $_ -and $_ -ne '127.0.0.1' -and $_ -ne '::1' }) if ($a.resetToDhcp -or $servers.Count -eq 0) { Set-DnsClientServerAddress -InterfaceAlias $a.alias -ResetServerAddresses -ErrorAction SilentlyContinue Write-Host "[ok] adapter '$($a.alias)' DNS reset to automatic (DHCP)" } else { Set-DnsClientServerAddress -InterfaceAlias $a.alias -ServerAddresses $servers -ErrorAction SilentlyContinue Write-Host "[ok] adapter '$($a.alias)' DNS restored to: $($servers -join ', ')" } } Remove-Item $stateFile } # SAFETY SWEEP -- always, even with a missing/stale state file. No adapter may be # left pointing at 127.0.0.1 (or ::1) once the daemon is gone, or the machine loses # ALL DNS ("server not responding"). This is the guarantee that a botched or # state-less uninstall can never take the user offline. foreach ($if in Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' -and ($_.ServerAddresses -contains '127.0.0.1') }) { Set-DnsClientServerAddress -InterfaceAlias $if.InterfaceAlias -ResetServerAddresses -ErrorAction SilentlyContinue Write-Host "[fix] adapter '$($if.InterfaceAlias)' was still pointed at the resolver -- reset to automatic (DHCP)" } # Remove the BNS root CA robustly -- by SUBJECT, not only the thumbprint recorded # in install-state.json. A missing or stale state file (the daemon was run by # hand, or this is an upgrade from an older build) must never leave an orphaned # trusted root in the machine store. Use X509Store direct because the Cert: # PSDrive is not always loaded in Inno's [UninstallRun] -NoProfile context. $removed = 0 $store = New-Object System.Security.Cryptography.X509Certificates.X509Store('Root','LocalMachine') $store.Open('ReadWrite') foreach ($c in @($store.Certificates | Where-Object { $_.Subject -match 'BNS Local Root CA' })) { $store.Remove($c) Write-Host "[ok] BNS Local Root CA removed ($($c.Thumbprint))" $removed++ } $store.Close() if ($removed -eq 0) { Write-Host "[ok] no BNS root CA left in the machine store" } try { Remove-Item -Path "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\Certificates" -Recurse -Force -ErrorAction Stop Write-Host "[ok] Firefox certificate policies removed (enterprise-roots + install)" } catch {} try { Remove-Item -Path "HKLM:\SOFTWARE\Policies\Mozilla\Firefox\DNSOverHTTPS" -Recurse -Force -ErrorAction Stop Write-Host "[ok] Firefox DNS-over-HTTPS policy removed (DoH restored to default)" } catch {} foreach ($task in "BNS Resolver Daemon", "BNS Sia Bridge") { try { Stop-ScheduledTask -TaskName $task -ErrorAction Stop } catch {} try { Unregister-ScheduledTask -TaskName $task -Confirm:$false -ErrorAction Stop Write-Host "[ok] scheduled task '$task' removed" } catch {} } Clear-DnsClientCache Write-Host "[done] system DNS configuration restored"