I wanted a quick report on a list of servers and see what DNS IPs they used. At the same time - if I was writing some PowerShell code already why not check if those DNS IPs were alive.
So here is what needed to be done:
Enumerate DNS IPs of all interfaces
This is the easy bit, just use WMI and take all data from all adapters which are IP enabled and have a default gateway defined.[array]$InterfaceList = gwmi win32_networkadapterconfiguration -ComputerName $srv | ?{$_.ipenabled -ieq "true" -and $_.DefaultIPGateway}
Read DNS IPs from each interface
This will be in the DNSServerSearchOrder property and you can assume it will be an array with as many IPs as many DNS servers the interface has. In my case, I know I have 3 everywhere so I might just hard code it into a loop to look at 3 elements:for ($i = 1; $i -le 3; $i++){
$script:obj.("DNS_" + $i) = $interface.DNSServerSearchOrder[$i]
}
Verify the given DNS IP to see if it's a live DNS server
This is the tricky bit. Not impossible though.. there are ugly solutions and some uglier ones. Why? The nice native method would be to perform a DNS lookup against the DNS server by using the System.Net.Dns class. The problem is that this class will always use the DNS server set on your local host and you can't specify one like with nslookup.So an ugly solution would be to run nslookup against the given DNS server and parse its text output. Or you could also change your DNS server on the local host on the fly and use System.Net.Dns. Another one is to see if UDP port 53 is open, it's at least 30 lines of code because as UDP is not a handshaking protocol, you need to setup a System.Net.Sockets.Udpclient, set encoding, initiate connection, handle errors, false positives...etc.
I decided to go with an easier one. By default, all DNS servers have the TCP port 53 open as well for large queries and zone transfers. That's much easier to test:
$Socket = New-Object System.Net.Sockets.TCPClient
$Connect = $Socket.BeginConnect($srv,53,$null,$null)
$Wait = $Connect.AsyncWaitHandle.WaitOne(3000,$false)
The below script takes a list of hosts from the pipe, enumerates 3 DNS IPs of each interface and checks if those DNS servers are alive and then lists the output in an object collection.
param ( [string] $log = "",
[string] $hosts = "")
#### Function for checking if a TCP port is opened on a host
function TCPportCheck ([string]$fsrv, [int]$port) {
$Socket = New-Object System.Net.Sockets.TCPClient
$Connect = $Socket.BeginConnect($fsrv,$port,$null,$null)
Start-Sleep 1
if($Connect.IsCompleted){
$Wait = $Connect.AsyncWaitHandle.WaitOne(3000,$false)
if(!$Wait){
$Socket.Close()
return $false
}
else{
$Socket.EndConnect($Connect)
$Socket.Close()
return $true
}
}
else{
return $false
}
}
$script:objColl = @()
#### Collate the host list.
$hostlist = @($Input)
if ($hosts) {
if($hosts -imatch " "){
$hostsArr = @($hosts.split(" "))
$hostlist += $hostsArr
}
else{
$hostlist += $hosts
}
}
foreach ($srv in $hostlist) {
# read list of interfaces
[array]$InterfaceList = gwmi win32_networkadapterconfiguration -ComputerName $srv | ?{$_.ipenabled -ieq "true" -and $_.DefaultIPGateway}
# go through each interface and read DNS IPS
if($InterfaceList.Count -gt 0){
foreach ($interface in $interfaceList){
#then check the DNS accessibility and lookup the DNS server name.
$script:obj = "" | select ComputerName,Access,InterfaceName,DNS_1,DNS_1_check,DNS_2,DNS_2_check,DNS_3,DNS_3_check,Result
$script:obj.ComputerName = $srv
$script:obj.Access = "OK"
$script:obj.InterfaceName = $interface.Description
$tmpResult = $null
for ($i = 0; $i -le 2; $i++){
$tmpIP = $tmpName = $null
$tmpIP = $interface.DNSServerSearchOrder[$i]
$tmpName = [System.Net.Dns]::GetHostByAddress($tmpIP).HostName
$script:obj.("DNS_"+($i+1)) = $tmpIP + " ($tmpName)"
if((TCPportCheck $tmpName 53)){
$script:obj.("DNS_"+($i+1)+"_Check") = "DNS port open"
}
else{
$script:obj.("DNS_"+($i+1)+"_Check") = "DNS port closed"
$tmpResult = "One or more DNS servers are not accessible"
}
}
if($tmpResult) {$script:obj.Result = $tmpResult}
else {$script:obj.Result = "OK"}
$script:objColl += $script:obj
}
}
}
$script:objColl
t