<# .SYNOPSIS Audits active network adapters to verify malware-filtering DNS configuration. .DESCRIPTION Retrieves all connected network adapters ('Up' status) and checks whether their configured DNS server addresses match an approved list of security-filtering DNS providers (e.g., Quad9 or Cloudflare for Families). Outputs a compressed JSON payload for RMM systems or Intune Custom Compliance discovery. .PARAMETER ApprovedDnsServers Array of IPv4 DNS server addresses considered compliant. Defaults to Quad9 (9.9.9.9, 149.112.112.11) and Cloudflare Security/Family (1.1.1.2, 1.0.0.2, 1.1.1.3, 1.0.0.3). .EXAMPLE .\Test-DnsCompliance.ps1 .EXAMPLE .\Test-DnsCompliance.ps1 -ApprovedDnsServers "9.9.9.9", "1.1.1.2" .NOTES Created: 2025-03-05 Modified: 2026-10-04 #> [CmdletBinding()] param ( [string[]]$ApprovedDnsServers = @( "9.9.9.9", # Quad9 Primary (Malware + DNSSEC) "149.112.112.11", # Quad9 Secondary (Malware + DNSSEC) "1.1.1.2", # Cloudflare Security Primary (Malware) "1.0.0.2", # Cloudflare Security Secondary (Malware) "1.1.1.3", # Cloudflare Family Primary (Malware + Adult) "1.0.0.3" # Cloudflare Family Secondary (Malware + Adult) ) ) # 1. Retrieve all active/connected network adapters $ActiveAdapters = Get-NetAdapter | Where-Object { $_.Status -eq 'Up' } if (-not $ActiveAdapters) { Write-Verbose "No active network adapters found on this endpoint." $NoAdapterOutput = [ordered]@{ Compliant = $true Reason = "No active network adapters found." Adapters = @() } return ($NoAdapterOutput | ConvertTo-Json -Compress) } $IsOverallCompliant = $true $AdapterAuditResults = [System.Collections.Generic.List[PSCustomObject]]::new() # 2. Audit DNS server assignments per active interface foreach ($Adapter in $ActiveAdapters) { # Query assigned IPv4 DNS server addresses $DnsConfig = Get-DnsClientServerAddress -InterfaceIndex $Adapter.InterfaceIndex -AddressFamily IPv4 -ErrorAction SilentlyContinue $ConfiguredServers = $DnsConfig.ServerAddresses # Verify if configured DNS contains at least one approved security DNS IP $MatchingServers = $ConfiguredServers | Where-Object { $ApprovedDnsServers -contains $_ } $IsAdapterCompliant = ($MatchingServers.Count -gt 0) # If any active adapter fails the check, mark the endpoint overall non-compliant if (-not $IsAdapterCompliant) { $IsOverallCompliant = $false Write-Verbose "Adapter '$($Adapter.Name)' (Index: $($Adapter.InterfaceIndex)) is NON-COMPLIANT. Configured: $($ConfiguredServers -join ', ')" } else { Write-Verbose "Adapter '$($Adapter.Name)' (Index: $($Adapter.InterfaceIndex)) is COMPLIANT. Configured: $($ConfiguredServers -join ', ')" } $AdapterAuditResults.Add([PSCustomObject]@{ AdapterName = $Adapter.Name InterfaceIndex = $Adapter.InterfaceIndex ConfiguredDns = $ConfiguredServers IsCompliant = $IsAdapterCompliant }) } # 3. Construct summary object and output JSON $ComplianceReport = [ordered]@{ Compliant = $IsOverallCompliant TestedAt = (Get-Date -Format 'yyyy-MM-dd HH:mm:ss') Adapters = $AdapterAuditResults } return ($ComplianceReport | ConvertTo-Json -Compress)