Overview:
Whether the engineer or sysadmin works in the realm of ‘networking’, ‘database’, or ‘Windows’, optimizing the throughput of machines is practical cursory knowledge. This post contains information that is considered a conjunction of these information technology domains.
Ping or ICMP works at the L2/L3 layers. Objects at those levels are called frames and packets. In this protocol, the sender uses the IP header to encapsulate the echo request marking (code 8). Less processing is required at the receiving side as the target simply swaps Source with Destination, resets TTL, marks the outgoing packet with a ‘reply’ identification (code 0). Receiver would immediately push the ICMP-Reply packet back to its default route for the intended IP.
Frames are blobs of data sent as a units over the data link. A packet is the chunk of data sent as a unit over the layer above (Transport – TCP/UDP/STP/SCCP). If the data link is made specifically for IP, such as Ethernet, the frame size and packet size (colloquially known as ‘payload’) will be matching in values after subtracting the protocol overhead from each layer.
L3 packets traverses through nodes that are called routers. Those L3 devices job is to determine the ‘next hop’ route. As a router passes packets to its bridge interface. Such interface is often connected to intermediary switches. Forwarding Tables are used to forward frames from one switch interface to another device. The wire or radio signal is considered Layer 1 (physical medium) where frames are encoded and decoded as binary to be transmitted.
Windows OS has methods to deal with layer 2 and 3. Legacy commands such as netsh will take arguments to modify L3 packet size, Maximum Transmission Unit (MTU). Frame sizes are controlled by a command Set-NetAdapterAdvancedProperty to set the JumboPacket property, which is the MTU plus L2 overhead of 14 bytes. Usually, only one of these commands is needed. the NetAdapterAdvancedProperty will become necessary if an interface has no IP properties, such as the case of members of a NIC Team. The script being provided will perform a ‘blanket approach’ to peruse both commands.
The manual way:
# Check the NICs
Get-NetIPInterface|select InterfaceAlias,NlMtu,AddressFamily
get-netadapter|select Name,MtuSize
# Set subject adapters
$adapterNames='NIC Team','NIC1','NIC2'
$mtuSize=9000
$jumboPacket=$mtuSize+14
foreach ($adapterName in $adapterNames){
invoke-expression "netsh interface ip set subinterface '$adapterName' mtu=$mtuSize store=persistent"
Set-NetAdapterAdvancedProperty -Name $adapterName -RegistryKeyword "*JumboPacket" -Registryvalue $jumboPacket
}
write-warning "Restarting adapters?`r`n$adapterNames"
pause
Restart-NetAdapter -name $adapterNames
# Double check the NICs
get-netadapter $adapterNames|select Name,MtuSize
Get-NetIPInterface $adapterNames|select InterfaceAlias,NlMtu
The Robotic Method
# optimizeMtu.ps1
# Description:
# This program automatically finds the optimal MTU transmission toward certain targets and adjust the network of the system to match its target
# Benefits of this optimization include (a) reduce CPU overhead due to packet fragmentation (b) increase overall data transmission throughput
# Requirements:
# PowerShell 3.0+
# All intermediary network L2 & L3 switches must support the initial MTU
# Out-of-band access to the host will be necessary to revert changes in case an incorrect value has been specified as the $expectedMtu
# WinRM access to the target remote computer
[string]$computername='SHERVER009'
[string]$jumboFrameTarget='iSCSIGateway'
[int]$expectedMtu=9000
$resetOtherAdapters=$false # set this value to only execute a reset on adapters not part of the route toward the $jumboFrameTarget
$resetAllAdapters=$false # set this value to $true to revert all adapters to the standard 1500 MTU
function optimizeAdapters{
param(
$computername=$env:computername,
$jumboFrameTarget='google.com',
$expectedMtu=1500,
$resetOtherAdapters=$false,
$resetAllAdapters=$false
)
# Program sequence:
# 1. Detect which interface is being used to send data toward $jumboFrameTarget
# 2. Change that interface's MTU to the expected value
# 3. Find optimized MTU
# 4. Change that interface's MTU to optimized value, if necessary
# Supporting functions section
function confirmation($content,$testValue="I confirm",$maxAttempts=3){
$confirmed=$false;
$attempts=0;
$content|write-host -ForegroundColor Yellow
write-host "Please review this content for accuracy.`r`n"
while ($attempts -le $maxAttempts){
if($attempts++ -ge $maxAttempts){
write-host "A maximum number of attempts have reached. No confirmations received!`r`n"
break;
}
$userInput = Read-Host -Prompt "Please type in this value => $testValue <= to confirm";
if ($userInput.ToLower() -ne $testValue.ToLower()){
cls;
$content|write-host
write-host "Attempt number $attempts of $maxAttempts`: $userInput does not match $testValue. Try again..`r`n"
}else{
$confirmed=$true;
write-host "Confirmed!`r`n";
break;
}
}
return $confirmed;
}
function findOptimalMtu($jumboFrameTarget){
[string]$ipAddress=[system.net.Dns]::GetHostAddresses($jumboFrameTarget).IPAddressToString
[int]$lowestMtu=1400 # Initial lower bound, this value will be updated
[int]$largestMtu=9600 # Upper bound value - expecting 10GiB Nics
[byte[]]$bufferArray=@(,$null*$largestMtu) # Shorthand constructor of an Array of Null values
function advancedPing{
param(
[string]$ipAddress='google.com',
[Array]$dataBuffer=@(,$null*9600),
[int]$ttl=100, # Expecting metro-link or local LAN
[bool]$dontFragment=$true
)
# Documentation: https://learn.microsoft.com/en-us/dotnet/api/system.net.networkinformation.ping?redirectedfrom=MSDN&view=netcore-3.1
$ping = New-Object System.Net.NetworkInformation.Ping # Instantiate a ping class from the C# .NET library
$pingOptions=New-Object System.Net.NetworkInformation.PingOptions
$pingOptions.DontFragment=$dontFragment # Reject any fragmentation, this is the default value
$pingOptions.Ttl=$ttl # Explicitly define TTL
return $ping.Send($ipAddress,$ttl,$dataBuffer,$pingOptions)
}
write-host "Discovering the optimal MTU transmission unit to target $jumboFrameTarget..."
Do {
[int]$testMtu=(($largestMtu - $lowestMtu)/2)+$lowestMtu
[Array]$payload=$bufferArray[1..$testMtu]
$pingReply=advancedPing $ipAddress $payload
$supportedMtu=$testMtu+28 # Account for IP/ICMP overhead
Write-Host "Testing supported MTU`t: $supportedMtu"
if ($pingReply.Status -match "Success"){
$lowestMtu = $testMtu
}else{
$largestMtu = $testMtu
}
$exitCondition=$lowestMtu -eq ($largestMtu-1)
}until($exitCondition)
If($lowestMtu -eq 1400){
Write-Error "$jumboFrameTarget is invalid."
}else{
return $lowestMtu+28
}
}
function setNicMtu{
param(
[string[]]$adapterNames='*',
[int]$mtuSize=1500
)
$jumboPacket=switch ($mtuSize+14){# Adding Layer 2 frame header overhead 14 bytes
{$_ -ge 9614}{9614;break}
{$_ -ge 9014}{9014;break}
{$_ -ge 4088}{4088;break}
default {1514}
}
# Perform sanity check prior to proceeding
$adapters=Get-NetAdapter $adapterNames #|?{$_.TransmitLinkSpeed –eq 10000000000}
$unmatchedAdapters=$adapters|?{$_.MtuSize -ne $mtuSize}
if($unmatchedAdapters){
write-verbose "These subject Adpapters do not match MTU $mtuSize`:`r`n$($unmatchedAdapters|select Name,MtuSize|out-string)"
foreach ($adapter in $unmatchedAdapters){
$adapterName=$adapter.Name
$existingMtu=$adapter.MtuSize
$isPhysical=$adapter.Virtual -eq $false
write-host "Modifying $(if($isPhysical){'physical'}else{'virtual'}) interface '$adapterName' from MTU $existingMtu to new value $mtuSize"
try{
# Layer 3: Some L3 interfaces do not have "*JumboPacket" registry keyword;
$null=invoke-expression "netsh interface ip set subinterface '$adapterName' mtu=$mtuSize store=persistent"
# Layer 2: Certain L2 NIC Team members or binded physical adapters require Windows registry configuration
Set-NetAdapterAdvancedProperty -Name $adapterName -RegistryKeyword "*JumboPacket" -Registryvalue $jumboPacket -ea Stop
}
catch{
write-warning $Error[0].exception.Message
}
}
# NIC Teams inherit the MTU settings of their parent interfaces. Hence, it's necessary to restart the adapters to changes to take effect
write-verbose "Restarting these adapters:`r`n$($unmatchedAdapters.Name|%{$_}|out-string)"
$unmatchedAdapters.Name|%{
write-verbose "Restarting adapter name '$_'"
$null=Restart-NetAdapter -name $_
}
$layer2AdaptersAfterRefresh=Get-NetAdapter $adapterNames
# netsh interface ipv4 show subinterfaces
$layer2Mismatches=$layer2AdaptersAfterRefresh.MtuSize|?{$_ -ne $mtuSize}
$layer3Mismatches=Get-NetIPInterface|?{$_.AddressFamily -eq 'IPv4' -and $_.NlMtu -ne $mtuSize -and $_.InterfaceAlias -in $layer2AdaptersAfterRefresh.Name}
if($layer2Mismatches -or $layer3Mismatches){
Write-warning "There were some mismatches between intended MTU $mtuSize and current Network Adapter settings"
write-host "$($layer2Mismatches|select Name,MtuSize|out-string)"
write-host "$($layer3Mismatches|select InterfaceAlias,NlMtu|out-string)"
return $false
}else{
return $true
}
}else{
write-host "Subject adapters already matched MTU $mtuSize`:`r`n$($adapters|select Name,MtuSize|out-string)"
return $true
}
}
function findSubjectAdapters($jumboFrameTarget){
$localAdapterToTarget=(find-netroute -RemoteIPAddress $([system.net.Dns]::GetHostAddresses($jumboFrameTarget))|select InterfaceAlias -Unique).InterfaceAlias
$nicTeam=.{try{Get-NetLbfoTeamNic $localAdapterToTarget -ea Stop}catch{$null}}
if($nicTeam){$nicTeamMembers=($nicTeam| Get-NetLbfoTeam).Members}
$subjectAdapters=@()
if($localAdapterToTarget){$subjectAdapters+=,$localAdapterToTarget}
if($nicTeam){$subjectAdapters+=,$nicTeam.Team}
if($nicTeamMembers -ne $null){
if($subjectAdapters.gettype() -eq $nicTeamMembers.gettype()){$subjectAdapters+=$nicTeamMembers}
else{$subjectAdapters+=,$nicTeamMembers}
}
Write-host "These are the subject adapters to target: $jumboFrameTarget`r`n$(Get-NetAdapter $subjectAdapters|select Name,MtuSize|out-string)"
return $subjectAdapters
}
function resetOtherAdaptersNotAssociated($jumboFrameTarget){
[int]$mtuSize=1500
[int]$jumboPacket=1514
$adapters=Get-NetAdapter
function findSubjectAdapters($jumboFrameTarget){
$localAdapterToTarget=(find-netroute -RemoteIPAddress $([system.net.Dns]::GetHostAddresses($jumboFrameTarget))|select InterfaceAlias -Unique).InterfaceAlias
$nicTeam=.{try{Get-NetLbfoTeamNic $localAdapterToTarget -ea Stop}catch{$null}}
if($nicTeam){$nicTeamMembers=($nicTeam| Get-NetLbfoTeam).Members}
$subjectAdapters=@()
if($localAdapterToTarget){$subjectAdapters+=,$localAdapterToTarget}
if($nicTeam){$subjectAdapters+=,$nicTeam.Team}
if($nicTeamMembers -ne $null){
if($subjectAdapters.gettype() -eq $nicTeamMembers.gettype()){$subjectAdapters+=$nicTeamMembers}
else{$subjectAdapters+=,$nicTeamMembers}
}
Write-host "These are the subject adapters to target: $jumboFrameTarget`r`n$($subjectAdapters|%{$_}|out-String)"
return $subjectAdapters
}
$subjectAdapters=findSubjectAdapters $jumboFrameTarget
$adapters=$adapters|?{$_.Name -notin $subjectAdapters}
$unmatchedAdapters=$adapters|?{$_.MtuSize -ne $mtuSize}
if($unmatchedAdapters){
write-verbose "These subject Adpapters do not match MTU $mtuSize`:`r`n$($unmatchedAdapters|select Name,MtuSize|out-string)"
foreach ($adapter in $unmatchedAdapters){
$adapterName=$adapter.Name
$existingMtu=$adapter.MtuSize
#$isPhysical=$adapter.Virtual -eq $false
#if ($isPhysical){
write-host "Modifying physical '$adapterName' from MTU $existingMtu to new value $mtuSize"
try{
# This directly affects NIC driver
$null=invoke-expression "netsh interface ip set subinterface '$adapterName' mtu=$mtuSize store=persistent"
# This controls Windows registry
Set-NetAdapterAdvancedProperty -Name $adapterName -RegistryKeyword "*JumboPacket" -Registryvalue $jumboPacket -ea Stop
}
catch{
write-warning $Error[0].exception.Message
}
}
write-verbose "Restarting these adapters:`r`n$($unmatchedAdapters.Name|%{$_}|out-string)"
$unmatchedAdapters.Name|%{
write-verbose "Restarting adapter name '$_'"
$null=Restart-NetAdapter -name $_
}
$adaptersAfterRefresh=Get-NetAdapter|?{$_.TransmitLinkSpeed –eq $linkSpeed}
$stillMismatches=$adaptersAfterRefresh.MtuSize|?{$_ -ne $mtuSize}
if($stillMismatches){
Write-host "There were some mismatches between intended MTU $mtuSize and current Network Adapter settings.`r`n$($stillMismatches|select Name,MtuSize|out-string)"
return $false
}else{
write-host "All other adapters not associated with $jumboFrameTarget have been set to MTU 1500"
return $true}
}else{
write-host "Subject adapters already matched MTU $mtuSize`:`r`n$($adapters|select Name,MtuSize|out-string)"
return $true
}
}
function resetAllAdapters{
[int]$mtuSize=1500
[int]$jumboPacket=1514
$adapters=Get-NetAdapter
$unmatchedAdapters=$adapters|?{$_.MtuSize -ne $mtuSize}
if($unmatchedAdapters){
write-verbose "These subject Adpapters do not match MTU $mtuSize`:`r`n$($unmatchedAdapters|select Name,MtuSize|out-string)"
foreach ($adapter in $unmatchedAdapters){
$adapterName=$adapter.Name
$existingMtu=$adapter.MtuSize
write-host "Modifying physical '$adapterName' from MTU $existingMtu to new value $mtuSize"
try{
# This directly affects NIC driver
$null=invoke-expression "netsh interface ip set subinterface '$adapterName' mtu=$mtuSize store=persistent"
# This controls Windows registry
Set-NetAdapterAdvancedProperty -Name $adapterName -RegistryKeyword "*JumboPacket" -Registryvalue $jumboPacket -ea Stop
}
catch{
write-warning $Error[0].exception.Message
}
}
write-verbose "Restarting these adapters:`r`n$($unmatchedAdapters.Name|%{$_}|out-string)"
$unmatchedAdapters.Name|%{
write-verbose "Restarting adapter name '$_'"
$null=Restart-NetAdapter -name $_
}
$adaptersAfterRefresh=Get-NetAdapter|?{$_.TransmitLinkSpeed –eq $linkSpeed}
$stillMismatches=$adaptersAfterRefresh.MtuSize|?{$_ -ne $mtuSize}
if($stillMismatches){
Write-host "There were some mismatches between intended MTU $mtuSize and current Network Adapter settings.`r`n$($stillMismatches|select Name,MtuSize|out-string)"
return $false
}else{
write-host "All other adapters not associated with $jumboFrameTarget have been set to MTU 1500"
return $true}
}else{
write-host "Subject adapters already matched MTU $mtuSize`:`r`n$($adapters|select Name,MtuSize|out-string)"
return $true
}
}
$isComputerNameLocal=$(.{[void]($computername -match '^([^.]+)\.{0,1}');return $matches[1]}) -eq $env:computername
if($resetAllAdapters){
if($isComputerNameLocal){return resetAllAdapters}
else{return invoke-command -computername $computername {param($resetAllAdapters)
[ScriptBlock]::Create($resetAllAdapters).invoke()} -Args ${function:resetAllAdapters}
}
}
elseif($resetOtherAdapters){
if($isComputerNameLocal){return resetOtherAdaptersNotAssociated $jumboFrameTarget}
else{return invoke-command -computername $computername {param($resetOtherAdaptersNotAssociated,$jumboFrameTarget)
[ScriptBlock]::Create($resetOtherAdaptersNotAssociated).invoke($jumboFrameTarget)} -Args ${function:resetOtherAdaptersNotAssociated},$jumboFrameTarget
}
}
else{
try{$session=New-PSSession -ComputerName $computername -ea Stop}catch{write-warning $error[0].Exception.Message}
if ($session){
# Sequence 1: Detect which interface is being used to send data toward $jumboFrameTarget
$subjectAdapters=invoke-command -Session $session -AsJob -ScriptBlock {
param($findSubjectAdapters,$jumboFrameTarget)
[ScriptBlock]::Create($findSubjectAdapters).invoke($jumboFrameTarget)
} -ArgumentList ${function:findSubjectAdapters},$jumboFrameTarget |Receive-Job -Wait
# Sequence 2: Change those interfaces' MTU to the expected value
$confirmed=confirmation -content "Please acknowledge that networking on $computername will be restarted. Services will be interrupted!"
if(!$confirmed){
write-warning "Procedure aborted. No changes have been made on $computername."
return $false
}else{
invoke-command -computername $computername -AsJob -ScriptBlock {
param($setNicMtu,$adapterNames,$expectedMtu)
[ScriptBlock]::Create($setNicMtu).invoke($adapterNames,$expectedMtu)
} -ArgumentList ${function:setNicMtu},$(,$subjectAdapters),$expectedMtu |Receive-Job -Wait
}
# Sequence 3: Find optimized MTU
write-host "Calibrating optimized MTU size to target $jumboFrameTarget..."
$optimalMtu=invoke-command -Session $session -AsJob -ScriptBlock {param($findOptimalMtu,$jumboFrameTarget)
[ScriptBlock]::Create($findOptimalMtu).invoke($jumboFrameTarget)
} -ArgumentList ${function:findOptimalMtu},$jumboFrameTarget |Receive-Job -Wait
# Sequence 4: Change that interface's MTU to optimized value, if necessary
if($optimalMtu -ne $expectedMtu){
$confirmed=confirmation -content "Reset network adapter(s) MTU size to $optimalMtu`?"
if($confirmed){
write-host "Now setting optimal MTU $optimalMtu to these interfaces:`r`n$($subjectAdapters|out-string)"
invoke-command -computername $computername -AsJob -ScriptBlock {
param($setNicMtu,$adapterNames,$optimalMtu)
[ScriptBlock]::Create($setNicMtu).invoke($adapterNames,$optimalMtu)
} -ArgumentList ${function:setNicMtu},$(,$subjectAdapters),$optimalMtu |Receive-Job -Wait
}else{
write-warning "MTU optimization cancelled."
$result=$false
}
}else{
write-host "Expected MTU of subject interfaces already matches with the optimal value`t: $optimalMtu"
$result=$true
}
Remove-PSSession $session
return $result
}
elseif($isComputerNameLocal){
$subjectAdapters=findSubjectAdapters $jumboFrameTarget
$confirmed=confirmation -content "Please acknowledge that networking on $computername will be restarted. Services will be interrupted!"
if(!$confirmed){
write-warning "Procedure aborted. No changes have been made on $computername."
return $false
}else{
setNicMtu $subjectAdapters $expectedMtu
}
write-host "Calibrating optimized MTU size to target $jumboFrameTarget..."
$optimalMtu=findOptimalMtu $jumboFrameTarget
if($optimalMtu -ne $expectedMtu){
$confirmed=confirmation -content "Reset network adapter(s) MTU size to $optimalMtu`?"
if($confirmed){
write-host "Now setting optimal MTU $optimalMtu to these interfaces:`r`n$($subjectAdapters|out-string)"
setNicMtu $subjectAdapters $optimalMtu
}else{
write-warning "MTU optimization cancelled."
$result=$false
}
}else{
write-host "Expected MTU of subject interfaces already matches with the optimal value`t: $optimalMtu"
$result=$true
}
return $result
}
else{
write-warning "Unable to Enter-Pssession to $computername"
return $false
}
}
}
optimizeAdapters $computername $jumboFrameTarget $expectedMtu $resetOtherAdapters $resetAllAdapters
# Sample Output:
#
#PS C:\Windows\system32> optimizeAdapters $computername $jumboFrameTarget $expectedMtu
#These are the subject adapters to target: ISCSIGATEWAY01
#
#Name MtuSize
#---- -------
#Nic Team 1500
#Nic Team1 1500
#NIC2 1500
#NIC1 1500
#
#
#
#Please acknowledge that networking on HYPERV-007 will be restarted. Services will be interrupted!
#Please review this content for accuracy.
#
#Please type in this value => I confirm <= to confirm: i confirm
#Confirmed!
#
#Modifying physical 'Nic Team1' from MTU 1500 to new value 9000
#WARNING: No matching MSFT_NetAdapterAdvancedPropertySettingData objects found by CIM query for instances of the
#ROOT/StandardCimv2/MSFT_NetAdapterAdvancedPropertySettingData class on the CIM server: SELECT * FROM
#MSFT_NetAdapterAdvancedPropertySettingData WHERE ((Name LIKE 'Nic Team')) AND ((RegistryKeyword = '*JumboPacket')).
#Verify query parameters and retry.
#Modifying physical 'Nic Team1' from MTU 1500 to new value 9000
#WARNING: No matching MSFT_NetAdapterAdvancedPropertySettingData objects found by CIM query for instances of the
#ROOT/StandardCimv2/MSFT_NetAdapterAdvancedPropertySettingData class on the CIM server: SELECT * FROM
#MSFT_NetAdapterAdvancedPropertySettingData WHERE ((Name LIKE 'Nic Team1')) AND ((RegistryKeyword =
#'*JumboPacket')). Verify query parameters and retry.
#Modifying physical 'NIC2' from MTU 1500 to new value 9000
#Modifying physical 'NIC1' from MTU 1500 to new value 9000
#WARNING: The network connection to HYPERV-007 has been interrupted. Attempting to reconnect for up to 4 minutes...
#WARNING: Attempting to reconnect to HYPERV-007 ...
#WARNING: The network connection to HYPERV-007 has been restored.
#True
#Calibrating optimized MTU size to target ISCSIGATEWAY01...
#Discovering the optimal MTU transmission unit to target ISCSIGATEWAY01...
#Testing supported MTU : 5528
#Testing supported MTU : 7578
#Testing supported MTU : 8603
#Testing supported MTU : 9116
#Testing supported MTU : 8860
#Testing supported MTU : 8988
#Testing supported MTU : 9052
#Testing supported MTU : 9020
#Testing supported MTU : 9004
#Testing supported MTU : 8996
#Testing supported MTU : 9000
#Testing supported MTU : 9002
#Testing supported MTU : 9001
#Expected MTU of subject interfaces already matches with the optimal value : 9000
#True
To modify a list of computers in a sequence:
$hyperVHosts <= https://blog.kimconnect.com/powershell-get-nic-mtus-of-all-hyper-v-hosts-in-domain-forest/
$computernames=$hyperVHosts
foreach ($computer in $computernames){
optimizeAdapters $computer $jumboFrameTarget $expectedMtu $resetOtherAdapters $resetAllAdapters
}
# Quick manual test to verify that the expected MTU is optimal
$mtuSize=9600
$jumboFrameNode='STORAGEGATEWAY'
$payload=$mtuSize-28 # Adding 20 bytes IP header + 8 bytes ICMP header
ping $jumboFrameNode -f -l $payload -n 1
# In case something goes wrong, here's the command to reconfigure NICs to standard MTUs
# Revert to standard MTU size
# optimizeMtu 'google.com' '*' $linkSpeed 1500
# This error will automatically resolve after the NIC team is restarted
#Set-NetAdapterAdvancedProperty : No matching MSFT_NetAdapterAdvancedPropertySettingData objects found by CIM query for
#instances of the ROOT/StandardCimv2/MSFT_NetAdapterAdvancedPropertySettingData class on the CIM server: SELECT * FROM
#MSFT_NetAdapterAdvancedPropertySettingData WHERE ((Name LIKE 'NIC Team')) AND ((RegistryKeyword ='*JumboPacket')). Verify query parameters and retry.
#At line:1 char:1
#+ Set-NetAdapterAdvancedProperty -Name $adapterName -RegistryKeyword "* ...
#+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# + CategoryInfo : ObjectNotFound: (MSFT_NetAdapter...ertySettingData:String) [Set-NetAdapterAdvancedProper
# ty], CimJobException
# + FullyQualifiedErrorId : CmdletizationQuery_NotFound,Set-NetAdapterAdvancedProperty
# legacy commands
# netsh interface ipv4 show interfaces
# netsh interface ipv4 set subinterface "'$adapterName'" mtu=$mtu store=persistent