Monthly Archive

Categories

DNS

Test DNS servers

Had a recent comment about testing DNS servers which got me thinking how do I test DNS servers.

I decided I wanted to get the DNS server address from the client, ping the DNS server to test network connectivity and test if DNS was up and working. The current result is this:

function test-dnsserver {
[CmdletBinding()]

## get-dns server address
$addresses = Get-DnsClientServerAddress -AddressFamily IPv4 -InterfaceAlias LAN |
Select-Object -ExpandProperty ServerAddresses

## test servers
foreach ($address in $addresses){
$resolved = $false
$ping = Test-Connection -TargetName $address -Quiet -Count 1
$server = Resolve-DnsName -Name $address -Server $address

if ($server.NameHost) {
$serverName = $server.NameHost
$resolved = $true
}
else {
$serverName = 'DNS unreachable'
}

$props = [ordered]@{
DNSserverName = $serverName
DNSserverIP = $address
Pingable = $ping
Resolved = $resolved
}

New-Object -TypeName PSObject -Property $props
}
}

 

I always set my network interface alias to LAN so you may want to change that or even make it a parameter.

 

Use Get-DNSCleintServerAddress from the DNSclient module to get the DNS server addresses.

 

Loop through the addresses – you could make this a single pipeline if you wanted rather than using foreach loop.

 

Run a ping test using Test-Connection. the version of Test-Connection in PowerShell core is truly horrible as it prints a whole load of stuff to screen even in quiet mode. One of these days I need to write a ping type function that actually works like I want – similar to the Windows PowerShell Test-Connection.

 

Use Resolve-DNSname, again from the DNSclient module, to resolve the server address on the DNS server. If thsi works you should get the DNS server name back in the NameHost property even if you don’t have a reverses lookup zone! Change resolved to $true in this case.

 

The results give you the DNS server name, IP address, if its ping able and if it can perform DNS resolution. If you can’t ping it then either the servers down or you have network problems. If it can’t perform the resolution then DNS is down or it doesn’t have a record for itself. Further investigation is then required.

 

Test isn’t perfect but it does give you a reasonable idea of where problems might be.

Finding DNS static records

An interesting question from the forums about finding DNS static records

 

You can view the records in a DNS zone

Get-CimInstance -Namespace root\MicrosoftDNS -ClassName MicrosoftDNs_Atype -ComputerName W16DC01  -Filter "DomainName = 'manticore.org'" |
select OwnerName, Timestamp, IPAddress

 

but how do you know which are static records.

 

There isn’t an obvious way to do it but if you dig into the records (hint create a static record and look at the differences) you’ll see that static records have a timestamp of 0

 

So to see just the static records

Get-CimInstance -Namespace root\MicrosoftDNS -ClassName MicrosoftDNs_Atype -ComputerName W16DC01 -Filter "DomainName = 'manticore.org' AND Timestamp = 0" |
select OwnerName, Timestamp, IPAddress

 

Rather than using the CIM class directly it’s simpler to use the cmdlets from the DNSserver module – install the remote admin tools to get access.

 

To view the A type records

Get-DnsServerResourceRecord -ComputerName W16DC01 -ZoneName 'manticore.org' -RRType A

 

To view the static records only

Get-DnsServerResourceRecord -ComputerName W16DC01 -ZoneName 'manticore.org' -RRType A |
where {-not $_.TimeStamp}

 

Notice that you’re checking for the absence of a timestamp

Creating DNS records

Following on from my previous post about creating a reverse lookup zone in DNS here’s a function to create records in that zone.

 

The function takes an IP address and name (of host) and uses Add-DnsServerResourceRecordA  to add the record to the forward lookup zone – I use my default AD zone.

 

The function then splits the IP address. Uses the last octet for the name in the reverse record. Creates the reverse lookup zone from the first 3 octets – notice how the range parameter is used in a decreasing way to specify the order of the octets – to create the reverse lookup zone. The host name and zone are used to create the FQDN of the host.

 

Add-DnsServerResourceRecordPtr  is used to create the reverse (PTR) record.

 

function new-dnsrecord {
  [CmdletBinding()]
  param (
    [string]$name,
    [string]$ipaddress,
    [string]$zone = 'Manticore.org'
  )

  Add-DnsServerResourceRecordA -Name $name -ZoneName $zone -AllowUpdateAny -IPv4Address $ipaddress

  $octs = $ipaddress -split '\.'

  $revname = "$($octs[3])"
  $revzone = "$($octs[2..0] -join '.').in-addr.arpa"
  $fqdn = "$name.$zone"
 
  Add-DnsServerResourceRecordPtr -Name $revname -ZoneName $revzone -AllowUpdateAny -PtrDomainName $fqdn

}

Create a reverse lookup zone

I needed to create a DNS reverse lookup zone for my test environment. With Windows Server 2012 R2 I’ve got cmdlets available for managing DNS servers – the DnsServer module. You need to install the DNS role or the DNS RSAT tools to get access to the module.

 

To create a new reverse lookup zone

Add-DnsServerPrimaryZone -DynamicUpdate Secure -NetworkId '10.10.54.0/24' -ReplicationScope Domain

 

Use the netorkId to define the subnet the zone spans. Setting DynamicUpdate to Secure ensures I have an AD integrated zone and I’ve set the replication scope to the domain.

 

Doesn’t get any easier

NSlookup in PowerShell

nslookup.exe is a command line executable that is used to discover the IP address of a remote machine from its FQDN. The results look something like this:

PS> nslookup powershell.org
DNS request timed out.
    timeout was 2 seconds.
Server:  UnKnown
Address:  192.168.0.1

Non-authoritative answer:
DNS request timed out.
    timeout was 2 seconds.
Name:    powershell.org
Addresses:  104.28.15.25
          104.28.14.25

 

The output is text – not the most useful of things to use.

 

One option if you want to perform lookups in PowerShell is to write your self a script

$ns = (nslookup.exe powershell.org )[-4..-3]
$lookup = [PSCustomObject]@{
  Name = ($ns[0] -split ':')[1].Trim()
  Address = ($ns[1] -split ':')[1].Trim()
}
$lookup

 

Run nslookup and take the 3rd and 4th lines from the end of the output. Then create an output object where the text in the array is split at the : the second element is used and trimmed of blank spaces.

 

If you like using .NET static methods you can do this:

PS> [System.Net.DNS]::GetHostEntry('powershell.org')

HostName       Aliases AddressList
--------       ------- -----------
powershell.org {}      {104.28.15.25, 104.28.14.25}

 

Best of all is the use the Resolve-DnsName cmdlet from the DnsClient module that’s present in Windows 8 and later

PS> Resolve-DnsName -Name 'powershell.org' | ft -a

Name           Type TTL Section IPAddress
----           ---- --- ------- ---------
powershell.org A    300 Answer  104.28.15.25

Error handling for DNS lookups

Interesting question on the forum regarding the Resolve-DNSname cmdlet. This is part of the DNSclient module introduced with Windows 8.

 

If the DNS record is found everything is good

£> Resolve-DnsName W12R2DSC -Server server02 | ft -a

Name                   Type TTL  Section IPAddress
----                   ---- ---  ------- ---------
W12R2DSC.Manticore.org A    1200 Answer  10.10.54.204

 

If the record isn’t found you get an error

£> Resolve-DnsName W12R2DSC3 -Server server02
Resolve-DnsName : W12R2DSC3 : DNS name does not exist
At line:1 char:1
+ Resolve-DnsName W12R2DSC3 -Server server02
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (W12R2DSC3:String) [Resolve-DnsName], Win32Exception
    + FullyQualifiedErrorId : DNS_ERROR_RCODE_NAME_ERROR,Microsoft.DnsClient.Commands.ResolveDnsName

 

If you want to gracefully handle that error you use try-catch

 

$computer = 'W12R2DSC3'
try {
Resolve-DnsName $computer -Server server02 -ErrorAction Stop
}
catch {
  Write-Warning -Message "Record not found for $computer"
}

Parsing ipconfig /displaydns with regular expressions

In yesterdays post I used a series of split operations to parse the strings produced by ipconfig /displaydns

 

Regular expressions should give a more power full way to perform this task. Not being a big fan of regular expressions I tend not to use them but for the sake of experimentation I thought I’d try and figure out a set of regex to use.

 

This is as far as I’ve got

 

$props = [ordered]@{
  RecordName = ""
  RecordType = ""
  Section    = ""
  TimeToLive = 0
  DataLength = 0
  Data       = ""
}

$recs = @()

$cache = ipconfig /displaydns
for($i=0; $i -le ($cache.Count -1); $i++) {
if ($cache[$i] -like '*Record Name*'){
    $rec = New-Object -TypeName psobject -Property $props
    $rec.RecordName = $cache[$i] -replace "(\s*\w*){2}(\s\.){5}(\s\:\s)", ""
    $rec.Section = $cache[$i+4] -replace "\s*\w*(\s\.){7}(\s\:\s)", ""
    $rec.TimeToLive = $cache[$i+2] -replace "(\s*\w*){3}\s(\s\.){4}(\s\:\s)", ""
    $rec.DataLength = $cache[$i+3] -replace "(\s*\w*){2}(\s\.){5}(\s\:\s)", ""
   
    $irec = ($cache[$i+5] -split ": ")
    $rec.RecordType = ($irec[0].TrimStart() -split ' ')[0]
    $rec.Data = $irec[1]

    $recs += $rec
}
else {
    continue
}
}

$recs | Format-Table –AutoSize

 

I still need to work out how to process the data and record type using regular expressions

Parsing ipconfig /displaydns

 

A recent question on the forum asked how you could get the contents on Windows 7 machines and earlier.

On later machines – Windows 8 and above -  its easy because you can use Get-DnsClientCache from the DnsClient module. This module is based on CIM classes that aren’t present on Windows 7 and earlier systems.

 

You can use ipconfig /displaydns to display the data but it looks like this

Record Name . . . . . : ns-nw.noaa.gov
Record Type . . . . . : 1
Time To Live  . . . . : 81966
Data Length . . . . . : 4
Section . . . . . . . : Additional
A (Host) Record . . . : 161.55.32.2

 

so you need to parse the strings into a format that you can work with. 

 

This is one solution

 

$props = [ordered]@{
  RecordName = ""
  RecordType = ""
  Section    = ""
  TimeToLive = 0
  DataLength = 0
  Data       = ""
}

$recs = @()

$cache = ipconfig /displaydns
for($i=0; $i -le ($cache.Count -1); $i++) {
if ($cache[$i] -like '*Record Name*'){
    $rec = New-Object -TypeName psobject -Property $props
    $rec.RecordName = ($cache[$i] -split -split ": ")[1]
    $rec.Section = ($cache[$i+4] -split -split ": ")[1]
    $rec.TimeToLive = ($cache[$i+2] -split -split ": ")[1]
    $rec.DataLength = ($cache[$i+3] -split -split ": ")[1]
   
    $irec = ($cache[$i+5] -split ": ")
    $rec.RecordType = ($irec[0].TrimStart() -split ' ')[0]
    $rec.Data = $irec[1]

    $recs += $rec
}
else {
    continue
}
}

$recs | Format-Table –AutoSize

Create an ordered hash table of output properties and an empty array to hold the results.

 

Get the output of  ipconfig /displaydns into $cache which will be an array of strings

Loop through $cache

 

if the record is like *Record Name*' then process that record and the next five records to give the results.  The actual data record is split twice to give the record type and the data – otherwise you’ll have to translate the numeric values in the Record Type line.

 

The results are put into an object which is added to the output array.

 

Continue looping through $cache until you meet the next line with a Record Name or end of file.

 

Finally display the results.

 

This works but is messy – I’m going to investigate alternatives

DNS client settings

Following yesterdays post there are a couple of other cmdlets worth looking at if you want to dig into the DNS settings on your client machines.

Get-DnsClient wil show you the DNS relsted settings for all of your network interfaces by default.  To investigate a single interface

 

£> Get-DnsClient -InterfaceAlias vEthernet* | fl

InterfaceAlias                     : vEthernet (External01)
InterfaceIndex                     : 20
ConnectionSpecificSuffix           :
ConnectionSpecificSuffixSearchList : {}
RegisterThisConnectionsAddress     : True
UseSuffixWhenRegistering           : False

InterfaceAlias                     : vEthernet (Internal01)
InterfaceIndex                     : 16
ConnectionSpecificSuffix           :
ConnectionSpecificSuffixSearchList : {}
RegisterThisConnectionsAddress     : True
UseSuffixWhenRegistering           : False

 

You can also see the DNS servers a particular interface will use:

£> Get-DnsClientServerAddress -InterfaceAlias vEthernet*

InterfaceAlias               Interface Address ServerAddresses
                             Index     Family
--------------               --------- ------- ---------------
vEthernet (External01)              20 IPv4    {192.168.0.1}
vEthernet (External01)              20 IPv6    {}
vEthernet (Internal01)              16 IPv4    {}
vEthernet (Internal01)              16 IPv6    {fec0:0:0:ffff::1, fec0:0:0:ffff::2, fec0:0:0:ffff::3}

Have you been talking to strangers?

Want to know the machines to which your machine has been connecting?

 

Try looking in the client DNS cache:

 

Get-DnsClientCache

 

will show a wealth of useful data.  All in the form:

£> Get-DnsClientCache | where Entry -like '*www.intelliweather.net*' | fl *

TTL                   : 39
Caption               :
Description           :
ElementName           :
InstanceID            :
Data                  : cache1.intelliweather.net
DataLength            : 8
Entry                 : www.intelliweather.net
Name                  : www.intelliweather.net
Section               : 1
Status                : 0
TimeToLive            : 39
Type                  : 5
PSComputerName        :
CimClass              : ROOT/StandardCimv2:MSFT_DNSClientCache
CimInstanceProperties : {Caption, Description, ElementName, InstanceID...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

TTL                   : 39
Caption               :
Description           :
ElementName           :
InstanceID            :
Data                  : 38.114.169.29
DataLength            : 4
Entry                 : www.intelliweather.net
Name                  : cache1.intelliweather.net
Section               : 1
Status                : 0
TimeToLive            : 39
Type                  : 1
PSComputerName        :
CimClass              : ROOT/StandardCimv2:MSFT_DNSClientCache
CimInstanceProperties : {Caption, Description, ElementName, InstanceID...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

 

 

What is interesting is the Time To Live settings on some of the records:

£> Get-DnsClientCache | sort TTL -Descending | group TTL -NoElement

Count Name
----- ----
    7 74538
    1 70203
    1 64639
    1 53300
    1 53299
    1 16441
    2 9308
    1 2579
    1 2573
    3 2475
    6 2469
    2 2327
    2 1986
    1 1890
    1 1089
    1 999
    2 899
    2 891
    2 878
    3 728
    1 724
    6 711
    1 631
    1 458
    1 412
    1 363
    1 133
   15 0

 

Some of those records will be around for a long time!