#Find-MaxMTU.ps1 #Alan dot Kaplan at va dot gov #10-1-2016 #version 2 adds collection of MTU for each hop #version 2.1 bug fixes, output to clipboard, pause if from PS cmd #version 2.2 minor cleanup for posting #requires -version 3 #http://stackoverflow.com/questions/32434882/powershell-tracert #I added -d to remove host name, maximum Function Invoke-Tracert { param([string]$RemoteHost) cls tracert -d $RemoteHost | ForEach-Object{ if($_.Trim() -match "Tracing route to .*") { Write-Host $_ -ForegroundColor Green } elseif ($_.Trim() -match "^\d{1,2}\s+") { $n,$a1,$a2,$a3,$target,$null = $_.Trim()-split"\s{2,}" if ($a1 -eq '*'){$iTimeoutCtr +=1}ELSE{$iTimeoutCtr = 0} $Properties = @{ Hop = $n; First = $a1; Second = $a2; Third = $a3; Node = $target } New-Object psobject -Property $Properties if ($iTimeoutCtr -eq $iMaxTimeOuts){ [void]{break;cls } } } } } #This is an minor adaptation of code here: #https://rcmtech.wordpress.com/2015/03/08/powershell-find-mtu/ Function Find-MTU($TestAddress){ Write-Host Finding MTU for $TestAddress -ForegroundColor Green $LastMinBuffer=$BufferSizeMin $LastMaxBuffer=$BufferSizeMax $MaxFound=$false #calculate first MTU attempt, halfway between zero and BufferSizeMax [int]$BufferSize = ($BufferSizeMax - 0) / 2 while($MaxFound -eq $false){ try{ $Response = ping $TestAddress -n 1 -f -l $BufferSize #if MTU is too big, ping will return: Packet needs to be fragmented but DF set. if($Response -like "*fragmented*"){throw} if($LastMinBuffer -eq $BufferSize){ #test values have converged onto the highest working MTU, stop here and report value $MaxFound = $true write-verbose "found." break } else { #it worked at this size, make buffer bigger write-verbose "$BufferSize" $LastMinBuffer = $BufferSize $BufferSize = $BufferSize + (($LastMaxBuffer - $LastMinBuffer) / 2) } } catch { #it didn't work at this size, make buffer smaller write-verbose "$BufferSize" $LastMaxBuffer = $BufferSize #if we're getting close, just subtract 1 if(($LastMaxBuffer - $LastMinBuffer) -le 3){ $BufferSize = $BufferSize - 1 } else { $BufferSize = $LastMinBuffer + (($LastMaxBuffer - $LastMinBuffer) / 2) } } write-verbose "," } [pscustomobject]@{ Address = $testaddress MTU = $BufferSize } } Function Find-AllMTUs{ $msg = "Stop trace after this number of timeouts" $iMaxTimeOuts= Run-TxtMsg $msg 2 if (!$iMaxTimeOuts ){Exit} [array]$hops = Invoke-Tracert $DestinationAddress $nodes = $hops.node #If you get a timeout, final is not collected. Add it back in $nodes += ($hops[$hops.getupperbound(0)] ).node $nodes | where {$_ -ne "Request timed out."} | select -Unique|% {Find-MTU $_} } Function Run-TxtMsg($msg,$defaultval){ $retval = Read-Host "$msg,`n[Enter for default value: $DefaultVal]" #use default if not specified if ($retVal.Length -eq 0) {$defaultval}ELSE{$retval} } Function Test-HostEntry($lookup){ Try{ if ([Net.IPAddress]::TryParse($lookup,[ref]$null)){ $z= [System.Net.Dns]::GetHostByAddress($lookup) }ELSE{ $z= [System.Net.Dns]::GetHostByName($lookup) } $True }Catch{$false} } Function Test-Command ($sCmdlet){ $retval = $true try{ get-command $sCmdlet -ea Stop | Out-Null }Catch{ Write-verbose "Command $sCmdlet not available" $retval = $false } $retval } #------------- Script Begins --------------- #set DestinationAddress to the name or IP address you wish to test against $DestinationAddress = Read-host "Run test to this IP or FQDN" if (!$DestinationAddress){Exit} $retval = Test-HostEntry $DestinationAddress if ( $retval -eq $false){ Write-Warning "Failed to ping $DestinationAddress!" Exit } $msg = "Set BufferSizeMax to the largest MTU you want to try, `nusually 1500 or up to 9000 if using Jumbo Frames" $BufferSizeMax = Run-TxtMsg $msg 1500 if (!$BufferSizeMax ){Exit} #Ed Wilson's method, https://technet.microsoft.com/en-us/library/ff730939.aspx $title = "Run Tracert?" $message = "Do you want to get the MTU for each hop found by by a trace route? This takes longer. 'No' is just to $destinationAddress`." $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Get MTU for each hop." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "Get MTU for $destinationaddress only." $cancel = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel", "Exit." $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $cancel) $result = $host.ui.PromptForChoice($title, $message, $options, 0) switch ($result) { 0 { $MTUList = Find-AllMTUs cls #Test for Core if ((Test-Command 'Out-GridView') -and (Test-Path "$env:windir\explorer.exe")){ $MTUList | Out-GridView -Title "MTUs for each hop to $DestinationAddress. Selected items will be copied to your clipboard" -PassThru | clip }ELSE{ cls $MTUList | format-table -auto #Pause if launched from shell with "Run with PowerShell" if (([Environment]::GetCommandLineArgs()) -match '&'){pause} } } 1 {Find-MTU $DestinationAddress} Default {Exit} }