02 February, 2013

Verify ComputerName remotely - OS

Quick question for you, my fellow IT engineers, how much do you trust the content of your DNS zone? Good question, isn't it? If a DNS zone and its servers are setup correctly (according to the size and requirements of the given infrastructure) then the content of DNS is supposed to be up-to-date, so DNS scavenging is setup to delete old records...etc.

However, in a global IT infrastructure, there's always someone rebuilding a server with a new name. Imagine this: there's a very enthusiastic engineer who is testing a new multicast OS build method by installing OS on 200+ virtual machines (VM). And to make this test more comprehensive, he/she rebuilds these VMs with new names 4-5 times - but keeps the IP addresses because changing the MAC <-> IP assignment would be too much hassle... yeah, you got it right, cleaning up DNS is not that much hassle at all?! :)
So at the end of the test we end up with ~800 incorrect DNS records (which we initially don't know about).

I've got scripts to check out different aspects of list of servers remotely and if I hit a name which points to an IP of one of those VMs and it already has a new name, then all remote queries will fail (while ping will be successful). Why? Because Windows has a so called Strict Name checking, it does not allow incoming connections if the connection has a different target name. (unless you disable this behaviour).

Solution:
To make sure my checks are transparent, I need to see if a server's name is different to what it was on my list. Here is an example code which can do that. For the sake of the simple example, I want to query the last boot time of each host on a list:

   
# get the IP of the server from DNS

   $ip = [System.Net.Dns]::GetHostAddresses($srv)[0].IPAddressToString

      # creating an object to store results
      $obj = "" | Select Computername,Real_computername,LastBootTime
      $obj.Computername = $srv

     
# reading the name of the computer (contacted via its IP) from WMI

      $obj.Real_computername = (gwmi -class Win32_ComputerSystem -ComputerName $ip).name

      
# reading boot time of the remote host

      $obj.LastBootTime = (gwmi -class Win32_OperatingSystem -ComputerName $ip).lastbootuptime

To explain the essential line:
$ip = [System.Net.Dns]::GetHostAddresses($srv)
This line returns an array, but this time I only care about the first IP, so the [0] element of the array, because I have only 1 IP for each sever.
The rest of the script is straightforward and commented.

Example output:
Computername          Real_computername       LastBootTime
------------          -----------------       ------------
R2D2                  NEWR2D2                 20130129000920.125000+060



Entire example code:
 ## Usage: PS C:\> gc hostlist.txt | getBootTime.ps1
  
 function PingServer ([string]$srv){
      $ping = new-object System.Net.Networkinformation.Ping
      Trap {Continue} $pingresult = $ping.send($srv, 3000, [byte[]][char[]]"z"*16)
      if($pingresult.Status -ieq "Success"){$true} else {$false}
 }
  
 $hostlist = @($Input)
 foreach($srv in $hostlist){
  
      # get the IP of the server from DNS
      $ip = [System.Net.Dns]::GetHostAddresses($srv)[0].IPAddressToString
  
      if(PingServer $ip){
  
           # creating an object to store results
           $obj = "" | Select Computername,Real_computername,LastBootTime
           $obj.Computername = $srv
  
           # reading the name of the computer (contacted via its IP) from WMI
           $obj.Real_computername = (gwmi -class Win32_ComputerSystem -ComputerName $ip).name
           # reading boot time of the remote host
           $obj.LastBootTime = (gwmi -class Win32_OperatingSystem -ComputerName $ip).lastbootuptime
           $objcoll += $obj
      }
 }  


May the Force...
t

No comments:

Post a Comment