SharePoint 2013 Environment Latency and Network Test Script

The intra-farm latency requirement of SharePoint is one of the hardware requirement, described at https://technet.microsoft.com/en-us/library/cc262485.aspx 

It can be difficult to test and is often left un-verified because short of having a server sit there and ping the rest of the farm for 10 minutes, there is no way to ensure that the environment is compliant.  To solve this, I have written a script that leaves one of the servers sitting around pinging the rest of the farm for 10 minutes and reports back on whether the environment complies.

The Script performs the following tests:

 - Check connectivity in the farm and make sure all servers are reachable. (this saves you from wasting 10 minutes waiting for the script to run only to find out the hosts weren't reachable)

 - Open an ODBC connection to the database server. (This is always handy)

 - Verify the environment meets the SharePoint hardware requirement that 99.9% of pings between servers in the farm take less than 1ms over a 10 minute period.  For convenience, how long this runs can be changed by setting the $RunTime variable to a lower value.

 

To run the script, either copy and paste the code into PowerShell_ISE and run it, or save it as a .ps1 file, right click it and select "Run with PowerShell".  The second method requires the powershell execution policy to be "unrestricted" (to set, run Set-ExecutionPolicy Unrestricted).

  #####Set Local Variables
 #Set Host Names, or IP Addresses
 $hostnames = "10.0.0.1", "SomeHost"
 #SQL Server Name\Instance
 $SQLname = "SQL\Instance"
 #Configure Run Time in Minutes (helpful for debugging)
 $RunTime = 10
 #Configure an allowance for late pings (in ms, one way)
 $allowance = 0
 #####
 
 ### test connectivity ###
 Write-Host "Test Connectivity:"
 
 Write-Host "Testing Ping"
 $ping = New-Object System.Net.NetworkInformation.ping
 
 foreach($a in $hostnames){
 $status = $ping.send($a).Status
 if($status -ne "Success"){
 throw "Ping Failed to $($a)"
 }
 }
 Write-Host " - Succeeded `n"
 
 
 
 ### test SQL connectivity ###
 Write-Host "Testing SQL Connection"
 $SQLConnection = New-Object System.Data.Odbc.OdbcConnection
 $SQLConnection.connectionstring = "Driver={SQL Server};Server=$SQLname"
 $SQLConnection.open()
 if($SQLConnection.state -ne "Open"){
 throw "SQL Connection Failed"
 }
 Write-Host " - Succeeded `n"
 
 
 
 ### Intra-server latency consistency test ###
 Write-Host "Start network consistency test"
 
 
 $ScriptBlock = {
 # accept the loop variable across the job-context barrier
 param($InHost, $RunTime) 
 
 $start = [DateTime]::Now
 $ping = New-Object System.Net.NetworkInformation.ping
 
 $PingResults = @()
 while([datetime]::now -le $start.AddMinutes($RunTime)){ 
 $outping = $ping.send($InHost)
 if($outping.Status -ne "Success"){
 $PingResults = $PingResults + 100
 } else{
 $PingResults = $PingResults + $outping.RoundtripTime
 }
 Start-Sleep .1
 } 
 return $PingResults
 }
 
 
 #run ping jobs in parallel
 foreach($i in $hostnames){
 Start-Job $ScriptBlock -ArgumentList $i, $RunTime -Name "$i.latency_test"
 }
 
 Write-Host "
 processing...`n"
 
 #wait and clean up
 While (Get-Job -State "Running") { Start-Sleep 5 }
 
 $output = @{}
 foreach($i in $hostnames){
 $output[$i] = Receive-Job -Name "$i.latency_test"
 }
 Remove-Job *
 
 #test results
 $LatencyTestFailed = 0
 foreach($i in $hostnames){
 $BadPings = $output[$i] | ?{$_/2 -ge 1 + $allowance}
 $PercentBadPings = $BadPings.length / $output[$i].Length * 100
 if($PercentBadPings -ge .1){
 "$i DOES NOT meet the latency requirements with $PercentBadPings % of pings >$(1+$allowance)ms" | Write-Host
 $LatencyTestFailed = 1
 } else{
 "$i meets the latency requirements with $PercentBadPings % of pings >$(1+$allowance)ms" | Write-Host
 }
 }
 if($LatencyTestFailed -eq 1){
 throw "Farm Latency Test Failed"
 }