A little while ago we have some issues with one of our Exchange environments. The symptoms was that basically everything was slow, opening address books, owa, sending mails and so on.
After some digging it occurred to me that this may be DNS related, so I used a one-liner in powershell to see how fast our DNS servers responded:
Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server x.x.x.x}
And sure enough, we were seeing response times in the range of 5-7 seconds. Way more than enough to cause our problems. After rebooting the DNS servers ours problems disappeared.
But, as always, I had to play around with created a powershell function.
The function resolves a few records from locally defined DNS servers and some publicly available DNS servers (or a custom list if you want) and measures the average latency (in milliseconds). The results are put in a list and sorted by latency.
Here’s the code:
function Measure-DNSLatency
{
[CmdletBinding()]
Param (
[string[]]$CustomDNSServer
)
try {
Get-DnsClientServerAddress -ErrorAction Stop | Out-Null
}
catch [System.Management.Automation.CommandNotFoundException] {
Throw "You need at least PowerShell v4.0, your version is: $(($PSVersionTable.psversion).Major)"
}
$report = @()
if ($CustomDNSServer.count -eq "0") {
Write-Verbose "Grabbing a list of locally defined dns servers"
$LocalDNSServers = (Get-DnsClientServerAddress).serveraddresses | Select-Object -Unique
$LocalDNSServers = $LocalDNSServers | Where-Object {$_ -ne "fec0:0:0:ffff::1"}
$LocalDNSServers = $LocalDNSServers | Where-Object {$_ -ne "fec0:0:0:ffff::2"}
$LocalDNSServers = $LocalDNSServers | Where-Object {$_ -ne "fec0:0:0:ffff::3"}
Write-Verbose "Measuring locally defined dns servers"
$progress = 1
foreach ($DNSServer in $LocalDNSServers) {
Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on locally defined servers" -Status "Measuring $((Resolve-DnsName $DNSServer -Server $DNSServer).NameHost)" -PercentComplete ($progress/$LocalDNSServers.count*100) -Id 1
$results = @()
$results += (Measure-Command {Resolve-DnsName cloud.kemta.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName a.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName b.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName c.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$object = New-Object PSObject
Add-Member -InputObject $object NoteProperty DNSServerName (Resolve-DnsName $DNSServer -Server $DNSServer).NameHost
Add-Member -InputObject $object NoteProperty DNSServerIP $DNSServer
Add-Member -InputObject $object NoteProperty LatencyInMS ($results | Measure-Object -Average).Average
$report += $object
$progress++
}
Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on locally defined servers" -Status "Done" -Id 1 -Completed
Write-Verbose "Measuring well known and publicly open dns servers"
$PublicDNSServers = New-Object System.Collections.ArrayList
$PublicDNSServers.Add("8.8.8.8") | Out-Null
$PublicDNSServers.Add("8.8.4.4") | Out-Null
$PublicDNSServers.Add("208.67.220.123") | Out-Null
$PublicDNSServers.Add("208.67.220.220") | Out-Null
$PublicDNSServers.Add("208.67.220.222") | Out-Null
$PublicDNSServers.Add("208.67.222.222") | Out-Null
$PublicDNSServers.Add("4.2.2.1") | Out-Null
$PublicDNSServers.Add("4.2.2.2") | Out-Null
$PublicDNSServers.Add("4.2.2.3") | Out-Null
$PublicDNSServers.Add("4.2.2.4") | Out-Null
$PublicDNSServers.Add("4.2.2.5") | Out-Null
$PublicDNSServers.Add("4.2.2.6") | Out-Null
$PublicDNSServers.Add("68.4.16.30") | Out-Null
$PublicDNSServers.Add("68.4.16.25") | Out-Null
$PublicDNSServers.Add("8.26.56.26") | Out-Null
$PublicDNSServers.Add("8.20.247.20") | Out-Null
$PublicDNSServers.Add("156.154.70.1") | Out-Null
$PublicDNSServers.Add("156.154.71.1") | Out-Null
$progress = 1
foreach ($DNSServer in $PublicDNSServers) {
Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on publicly available servers" -Status "Measuring $((Resolve-DnsName $DNSServer -Server $DNSServer).NameHost)" -PercentComplete ($progress/$PublicDNSServers.count*100) -Id 1
$results = @()
$results += (Measure-Command {Resolve-DnsName cloud.kemta.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName a.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName b.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName c.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$object = New-Object PSObject
Add-Member -InputObject $object NoteProperty DNSServerName (Resolve-DnsName $DNSServer -Server $DNSServer).NameHost
Add-Member -InputObject $object NoteProperty DNSServerIP $DNSServer
Add-Member -InputObject $object NoteProperty LatencyInMS ($results | Measure-Object -Average).Average
$report += $object
$progress++
}
Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on publicly available servers" -Status "Done" -Id 1 -Completed
}
else {
Write-Verbose "Measuring custom dns servers"
$progress = 1
foreach ($DNSServer in $CustomDNSServer) {
Write-Progress -ErrorAction SilentlyContinue -Activity "Measuring Latency on custom servers" -Status "Measuring $((Resolve-DnsName $DNSServer -Server $DNSServer).NameHost)" -PercentComplete ($progress/$CustomDNSServer.count*100) -Id 1
$results = @()
$results += (Measure-Command {Resolve-DnsName cloud.kemta.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName google.com -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName a.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName b.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$results += (Measure-Command {Resolve-DnsName c.root-servers.net -DnsOnly -Type A -NoHostsFile -server $DNSServer -ErrorAction SilentlyContinue}).TotalMilliSeconds
$object = New-Object PSObject
Add-Member -InputObject $object NoteProperty DNSServerName (Resolve-DnsName $DNSServer -Server $DNSServer).NameHost
Add-Member -InputObject $object NoteProperty DNSServerIP $DNSServer
Add-Member -InputObject $object NoteProperty LatencyInMS ($results | Measure-Object -Average).Average
$report += $object
$progress++
}
}
$report | Sort-Object LatencyInMS
<#
.Synopsis
Measures DNS Latency
.Description
Grabs locally defined dns servers and some publicly available dns servers and measures the Latency (in milliseconds) on DNS queries from your computer to them
.Parameter CustomDNSServer
Specifies a custom list of DNS servers to measure, or it could be a single server
.Example
Measure-DNSLatency
Measures DNS latency on locally defined DNS servers og some public available DNS servers
.Example
Measure-DNSLatency 8.8.8.8
Measures the DNS latency only on the DNS server 8.8.8.8
.Example
Measure-DNSLatency 8.8.8.8,8.8.4.4
Measures the DNS latency only on the DNS servers 8.8.8.8 and 8.8.4.4
.Link
http://cloud.kemta.net
#>
}
The different outputs will look something like this:
hi,
i tested with dig command on same computer, same time.
But powershell gave 3 more delays. i think dig gives more accureta result than powershell. What do you think about this ?
poweshell command:
while ($true){ (Measure-Command {Resolve-DnsName mynet.com -Server 8.8.8.8 }).TotalMilliseconds;sleep 2
Write-Host (get-date)}
bash command: (windows10 bash on ubuntu on windows commandline)
while true ;do date;dig mynet.com |egrep “212.|time”;sleep 2;echo date ; done