06 April, 2015

Verify forward and reverse DNS records - OS

DNS is a fairly simple and usually reliable service - when it works. People don't really think about it unless there are weird issues with an application and they spent 2 days troubleshooting it and just because they want to make sure they looked at everything, they check DNS and it turns out that those weird issues are in fact caused by e.g. missing reverse records.

These issues manifest in applications behaving strangely often providing uselessly generic errors messages or even worse, some misleading ones. After a very tedious issue over a weekend which required repeated checkouts across a globally distributed AD integrated DNS zone, I thought I wouldn't do this manually all the time with excel magic but via a script.

Steps needed to be made:
  • Take a list of server names (ideally FQDNs)
  • Perform a forward lookup to get the IP address(es) of each server
  • Take those IPs and perform a reverse lookup on them
  • Mark each host and IP with error if either the forward or reverse lookups fail or the reverse lookup provides a different hostname than the server name provided

Forward lookup (filtering on IPv4 only):
[array]$IPAddresses = [System.Net.Dns]::GetHostAddresses($obj.ComputerName) | ?{$_.AddressFamily -eq "InterNetwork"} | %{$_.IPAddressToString}


Reverse lookup:
$tmpreverse = [System.Net.Dns]::GetHostByAddress($_).HostName

Output:






The full script (simplified version):

 $hostlist = @($input)  
   
 # running through the list of hosts  
 $hostlist | %{  
      $obj = "" | Select ComputerName,Ping,IPNumber,ForwardLookup,ReverseLookup,Result  
      $obj.ComputerName = $_  
   
      # ping each host  
      if(Test-Connection $_ -quiet){  
           $obj.Ping = "OK"  
     $obj.Result = "OK"  
      }  
      else{  
           $obj.Ping = "Error"  
     $obj.Result = "Error"  
      }  
        
      # lookup IP addresses of the given host  
      [array]$IPAddresses = [System.Net.Dns]::GetHostAddresses($obj.ComputerName) | ?{$_.AddressFamily -eq "InterNetwork"} | %{$_.IPAddressToString}  
   
      # caputer count of IPs  
      $obj.IPNumber = ($IPAddresses | measure).count  
        
      # if there were IPs returned from DNS, go through each IP  
   if($IPAddresses){  
     $obj.ForwardLookup = "OK"  
   
        $IPAddresses | %{  
             $tmpreverse = $null  
                  
                # perform reverse lookup on the given IP  
             $tmpreverse = [System.Net.Dns]::GetHostByAddress($_).HostName  
             if($tmpreverse){  
                  
                     # if the returned host name is the same as the name being processed from the input, the result is OK  
                  if($tmpreverse -ieq $obj.ComputerName){  
                       $obj.ReverseLookup += "$_ : OK `n"  
                  }  
                  else{  
                       $obj.ReverseLookup += "$_ different hostname: $tmpreverse `n"  
                       $obj.Result = "Error"  
                  }  
             }  
             else{  
                  $obj.ReverseLookup = "No host found"  
                  $obj.Result = "Error"  
             }  
     }  
      }  
      else{  
           $obj.ForwardLookup = "No IP found"  
           $obj.Result = "Error"  
      }  
        
      # return the output object  
      $obj  
 }  


t


15 comments:

  1. Hi Mate,
    Awesome script. I'm new to PS scripting.
    Wondering if the script could be fine tweaked to list reverse DNS record of particular subnet? Would be great if you could help.

    Thanks
    Jit

    ReplyDelete
    Replies
    1. Do you mean the list of reverse zones like 0.168.192.in-addr.arpa?
      For that the System.Net.DNS is useless unfortunately. I found a way but you need to be an admin on the Windows DNS server to be able to access it via WMI:
      gwmi -class microsoftdns_zones -namespace root/microsoftdns | select name

      Delete
  2. It's possible for an IP map back to two hostnames (e.g. a host may have two websites that have https and require two different common names for their certificates - one way of doing that is to simply add another fqdn but same IP), so I'm not sure that should be marked as a failure. It might be better marked as investigate, or simply IP has multiple hostnames.....etc

    ReplyDelete
    Replies
    1. Valid point, I agree. In my use case I really needed a 1 to 1 match and I also simplified the script compared to the one I use to make the main logic easy to read and easy to modify.
      You can also add checks to make sure you have all the aliases that you expect, add log entries to the script...etc. so feel free to use it and change it to fit your environment.
      Thanks for the comment.

      Delete
  3. How would you read a list of systems and pipe it to the script

    ReplyDelete
    Replies
    1. You either have a list in a CMDB type database or you could get it from AD, e.g.
      import-module activedirectory
      get-adcomputer -filter {enabled -eq $true} | %{$_.name} | yourDNSLookupscript.ps1

      Delete
    2. Great script Tompa! Very helpful.

      Luis,
      Regarding reading a list of files, all you have to do is run get-conent $file and pipe it to the script Tompa posted. This is what I did:
      file has to have hostname.domain.com on each line
      $file = "c:\temp\file.txt"
      Get-Content $file| .\verifyDnsForwardReverseRecords.ps1 | ft -AutoSize

      Delete
    3. Great script Tompa! Very helpful.

      Luis,
      Regarding reading a list of files, all you have to do is run get-conent $file and pipe it to the script Tompa posted. This is what I did:
      file has to have hostname.domain.com on each line
      $file = "c:\temp\file.txt"
      Get-Content $file| .\verifyDnsForwardReverseRecords.ps1 | ft -AutoSize

      Delete
    4. Great script Tompa! Very helpful.

      Luis,
      Regarding reading a list of files, all you have to do is run get-conent $file and pipe it to the script Tompa posted. This is what I did:
      file has to have hostname.domain.com on each line
      $file = "c:\temp\file.txt"
      Get-Content $file| .\verifyDnsForwardReverseRecords.ps1 | ft -AutoSize

      Delete
    5. Great script Tompa! Very helpful.

      Luis,
      Regarding reading a list of files, all you have to do is run get-conent $file and pipe it to the script Tompa posted. This is what I did:
      file has to have hostname.domain.com on each line
      $file = "c:\temp\file.txt"
      Get-Content $file| .\verifyDnsForwardReverseRecords.ps1 | ft -AutoSize

      Delete
  4. Very good, thank you!

    ReplyDelete
  5. Please help in amending the script in exporting the results to Txt / CSV files.

    ReplyDelete
    Replies
    1. you can just export it as you run the script and use export-csv command, so if you run the script like this, it will export the results to a csv file:
      PS C:\> gc list.txt | verifyDNS.ps1 | export-csv c:\temp\DNSresult.csv

      Delete
  6. Hi,

    How to get the ip addresses for the FQDN with forward lookup ? so we can have a complete picture ?

    Thanks,

    ReplyDelete
    Replies
    1. you can just use the GetHostByName method, e.g.:
      PS C:\Users\tompa> [System.Net.Dns]::getHostByName("r2d2srv.tatooine.com")

      Delete