PowerShell: Find MTU

I had some issues caused by MTU recently, and decided to write a script to test for the Maximum Transmission Unit that a network or host could cope with.

I originally started off by using the PowerShell Test-Connection cmdlet, but then realised that it doesn’t allow you to set the DF bit (do not fragment) which is required for MTU testing, so I switched it out for the ping command.

The script works by trying buffer sizes that are calculated as the halfway point between a minimum and maximum value. These two points converge as the preceding test either passes or fails, which makes for a fairly swift determination of the MTU.

#set BufferSizeMax to the largest MTU you want to try, usually 1500 or up to 9000 if using Jumbo Frames
$BufferSizeMax = 1500
#set TestAddress to the name or IP address you wish to test against
$TestAddress   = "www.bbc.co.uk"

$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-Host "found."
            break
        } else {
            #it worked at this size, make buffer bigger
            Write-Host "$BufferSize" -ForegroundColor Green -NoNewline
            $LastMinBuffer = $BufferSize
            $BufferSize = $BufferSize + (($LastMaxBuffer - $LastMinBuffer) / 2)
        }
    } catch {
        #it didn't work at this size, make buffer smaller
        Write-Host "$BufferSize" -ForegroundColor Red -NoNewline
        $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-Host "," -ForegroundColor Gray -NoNewline
}
Write-Host "MTU: $BufferSize"

This entry was posted in Networking, PowerShell, Scripting and tagged , , , , , , , , . Bookmark the permalink.

5 Responses to PowerShell: Find MTU

  1. Adam says:

    Great script. Thank you for sharing.

    Like

  2. Herbert says:

    hi, great script but buffersize is not mtu size. you need to add 28 bytes and therefore the resulting statement is misleading.

    $mtu = $BufferSize + 28
    Write-Host “MTU Size: $mtu”

    https://en.code-bude.net/2017/02/18/tool-mtu-optimizer-automatically-find-the-best-mtu/

    otherwise, AWESOME

    Like

  3. Jeremiah says:

    While the binary reduction in your script will hone down on a the lowest mtu in a path, it will not find higher mtu’s of other routers in the path. You may need to test every possible packet size above fragmentation point without the -d to find mismatches (gaps) when going through multiple routers, firewalls, tunnels, etc.

    Like

  4. Alex says:

    PS 5.1 with NoFragmentation
    Get-WmiObject -Class Win32_PingStatus -computer $ComputerName -Filter “Address=’$server’ AND Timeout=1000 AND BufferSize=$BufferSize AND NoFragmentation=TRUE”

    Like

  5. Guruniverse says:

    Excellent script and agree with Herbert that the MTU is actually the $Buffersize + 28 => MTU == ping max payload ($Buffersize) + 8 bytes ICMP overhead + 20 bytes IP overhead.

    For exotic users like me who also use Powershell on a Mac you will need to change the ping command accordingly:

    $Response = ping $TestAddress -c 1 -D -s $BufferSize 2>&1

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.