# Tests a number of ways Huntress agents communicate with the Huntress portal # Output is to standard out as well as the file represented by $DebugLog # # <<< PowerShell version >>> $latestUpdate = "Huntress Network Tester, Windows PowerShell, last updated: June 5, 2026" # adds time stamp to a message and then writes that to the log file $DebugLog = "c:\Windows\temp\huntress_network_test.log" function logger ($msg) { $TimeStamp = "[{0:yyyy/MM/dd} {0:HH:mm:ss}]" -f (Get-Date) Add-Content $DebugLog "$TimeStamp $msg" Write-Output "$msg" } logger "-----------------------------------------------------------------------------" logger $latestUpdate logger "-----------------------------------------------------------------------------" # for the summary, keeps track of failures for a conclusive singular pass/fail at the end $countFails=0 # Avoid "First Run Customize" blocking the testing by disabling it Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Internet Explorer\Main" -Name "DisableFirstRunCustomize" -Value 2 # Force TLS 1.2 to avoid compatibility issues and ensure accurate testing (Huntress uses TLS 1.2+ only) try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch { logger "Failed to enable TLS 1.2, Huntress requires TLS 1.2 or higher for security reasons." exit 1 } # retrieve URLs, cert Issuer, and cert Subject from Huntress github $URL = 'https://raw.githubusercontent.com/huntresslabs/support/refs/heads/main/URLdata.json' try { $data = (Invoke-WebRequest -Uri $URL -UseBasicParsing -ErrorAction Stop).Content | ConvertFrom-Json } catch { logger "Fallback using WebClient (still uses TLS 1.2)" $wc = New-Object System.Net.WebClient $wc.Headers['User-Agent'] = 'HuntressSupportScript' try { $jsonString = $wc.DownloadString($URL) } catch { logger "Unable to connect to github, connectivity to raw.githubusercontent.com is required for this script!" logger "Please contact Huntress Support if you have a business requirement for blocking githubusercontent.com and still need to test connectivity." exit 1 } try { $data = $jsonString | ConvertFrom-Json } catch { logger "Failed to parse JSON from github: $_" exit 1 } } # process the data from github $testURLs = @($data.array1) $certURLs = @($data.array2) $certTemp = @($data.array4) $expIssuerName = @($data.array5) $expSubject = @() $expIssuer = @() # array4 contains two different sets of info, even indices are subject, odd indices are issuer for ($i = 0; $i -lt $certTemp.Count; $i++) { if ($i % 2 -eq 0) { $expSubject += $certTemp[$i] } else { $expIssuer += $certTemp[$i] } } # Simple test just to establish working DNS and basic internet connectivity logger "-- Testing DNS resolution and port 80 connectivity --" try { $pageOutput = $(Invoke-WebRequest "https://huntress.io" -UseBasicParsing) if ($pageOutput.StatusCode -eq 200) { $pageOutput = $($pageOutput.Content) | Select-Object -First 20 $startIndex = $pageOutput.IndexOf("") if ($startIndex -ne -1) { $contentStart = $startIndex + 7 $result = $pageOutput.Substring($contentStart, 27) logger "[DNS Resolution / port 80 connection successful]" } else { logger "The tag '<title>' was not found." $countFails++ } } else { logger "[FAILED: DNS and port 80 checks]" logger "Output: $pageOutput" $countFails++ } } catch { logger "Error interacting with Invoke-WebRequest: $_" $countFails++ } logger "" # tests that the expected certificates are not intercepted. If the expected cert is not returned the agent will not function. logger "-- Testing Certificate Validation --" $failCounter = 0 for ($i = 0; $i -lt $certURLs.Count; $i++) { $cleanURL = ($certURLs[$i] -replace '^https://', '') -replace '/.*','' $uri = ([uri]$cleanURL) $tcp = New-Object Net.Sockets.TcpClient $tcp.Connect("$uri", 443) $ssl = New-Object Net.Security.SslStream($tcp.GetStream(),$false,{$true}) $ssl.AuthenticateAsClient($uri) $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $ssl.RemoteCertificate $recSubject = $cert.Subject $recIssuer = $cert.Issuer # retrieve a hashed/encrypted version of the certificate to log in case troubleshooting is required $PEM = @" -----BEGIN CERTIFICATE----- $([System.Convert]::ToBase64String($cert.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Cert), [System.Base64FormattingOptions]::InsertLineBreaks)) -----END CERTIFICATE----- "@ if ($recSubject -eq $expSubject[$i]) { logger "[Certificate subject validation successful for $cleanURL]" } else { logger "[FAILED: Subject validation. Certificate does not match for [$cleanURL] !]" logger "Subject that was returned: [$recSubject]" logger "Subject that was expected: [$($expSubject[$i])]" $failCounter++ $countFails++ } # Issuer can vary based on the specific server the script reaches. To compensate, we check for exact match then a wildcard match. if ($recIssuer -eq $expIssuer[$i]) { logger "[Certificate issuer validation successful for $cleanURL]" } else { if ($recIssuer -like "*$($expIssuerName[$i])*") { logger "Please note this was not an exact match, which is expected with big infrastructure." logger "Issuer that was returned: [$recIssuer]" logger "Issuer that was expected: [$($expIssuer[$i])]" } else { logger "[FAILED: Issuer validation. Certificate does not match for [$cleanURL] !]" logger "Issuer that was returned: [$recIssuer]" logger "Issuer that was expected: [$($expIssuer[$i])]" logger "PEM that was received: $PEM" $failCounter++ $countFails++ } } $ssl.Dispose() $tcp.Close() } if ($failCounter -gt 0) { logger "" logger "------------------------------------------------------------------------------------------------------------------------------" logger "The Subject/Issuer text above usually identifies if this is a DPI/cert interception issue, or a cert chain issue." logger "* If the returned SUBJECT does not contain 'Huntress' or 'Microsoft' in the text this is likely a DPI/cert interception issue." logger " You'll need to add an exclusion for the certificate for this URL in your DPI/cert interception service: $cleanURL" logger "* If the returned ISSUER does not contain 'DigiCert', 'Google', or 'Microsoft', this is likely a DPI/cert interception issue." logger " You'll need to add an exclusion for the certificate for this URL in your DPI/cert interception service: $cleanURL" logger "* Otherwise this is likely a missing certificate chain. Check for pending OS updates, reboot, and try again." logger "------------------------------------------------------------------------------------------------------------------------------" } logger "" # test outgoing port 443 connectivity to Huntress URLs logger "-- Verifying Huntress services can be reached --" foreach ($testURL in $testURLs) { $tcp = New-Object System.Net.Sockets.TcpClient try { $cleanURL = $($testURL -replace '^https://', '') -replace '/.*','' $tcp.connect($cleanURL, 443) logger "[Connection to $cleanURL successful]" } catch { logger = "WARNING, connectivity to Huntress URL's is being interrupted. You MUST open port 443 for $cleanURL in order for the Huntress agent to function." logger "Error: $($_.Exception.Message)" $countFails++ } finally { $tcp.Close() } } logger "" if ($countFails -gt 0) { logger "[FAILED to connect to all Huntress services]" logger "------------------------ FAILED network test ----------------------------------" } else { logger "[Successfully connected to Huntress services]" logger "---------------------- Network testing complete --------------------------------" }