Display port count per IP address

This script checks for port exhaustion on a specific server (Source).

Port exhaustion can cause all kinds of problems for your servers. Here’s a list of some symptoms:

  • Users won’t be able to connect to file shares on a remote server
  • DNS name registration might fail
  • Authentication might fail
  • Trust operations might fail between domain controllers
  • Replication might fail between domain controllers
  • MMC consoles won’t work or won’t be able to connect to remote servers

Interesting article about the network port exhaustion > here

## Author: frank.taglianetti@microsoft.com

## Displays port counts per  IP address
## Parameters = none
## Modified 12/6/2011 to include Windows Vista or later
## TCP Parameters documented in http://support.microsoft.com/kb/953230

function MaxNumOfTcpPorts  #helper function to retrive number of ports per address
{
	param
	(
		[parameter(Mandatory=$true)]
		$tcpParams
	)
	#  Returns the maximum number of ports per TCP address
	#  Check for Windows Vista and later
	$IsVistaOrLater = Get-WmiObject -Class Win32_OperatingSystem | %{($_.Version -match "6\.\d+")}
	if($isVistaOrLater)
	{
		# Use netsh to retrieve the number of ports and parse out the string of numbers after "Number of Ports : "
		$maxPorts = netsh int ip show dynamicport tcp |
		Select-String -Pattern "Number of Ports : (\d*)"|
		%{$_.matches[0].Groups[1].Value}
		# Convert string to integer
		$maxPorts = [int32]::Parse($maxPorts)
		#  modify the PSCustomObject to simulate the MaxUserPort value for printout
		Add-Member -InputObject $tcpParams -MemberType NoteProperty -Name MaxUserPorts -Value $maxPorts
	}
	else  # this is Windows XP or older
	{
		# check of emphermal ports modified in registry
		$maxPorts = $($tcpParams | Select-Object MaxUserPort).MaxUserPort
		if($maxPorts -eq $null)
		{
			$maxPorts = 5000 - 1kb    #Windows Default range is from 1025 to 5000 inclusive
			Add-Member -InputObject $tcpParams -MemberType NoteProperty -Name MaxUserPort -Value $maxPorts
		}
	}
	return $maxPorts
}

function New-Port  # helper function to track number of ports per IP address
{
	Param
	(
		[string] $IPAddress = [String]::EmptyString,
		[int32] $PortsWaiting = 0,
		[int32] $MaxUserPort = 3976
	)

	$newPort = New-Object PSObject

	Add-Member -InputObject $newPort -MemberType NoteProperty -Name IPAddress -Value $IPAddress
	Add-Member -InputObject $newPort -MemberType NoteProperty -Name PortsUsed -Value 1
	Add-Member -InputObject $newPort -MemberType ScriptProperty -Name PercentUsed -Value {$this.PortsUsed / $this.MaxUserPort}
	Add-Member -InputObject $newPort -MemberType NoteProperty -Name PortsWaiting -Value $portsWaiting
	Add-Member -InputObject $newPort -MemberType ScriptProperty -Name PercentWaiting -Value {$this.PortsWaiting / [Math]::Max(1,$this.PortsUsed)}
	Add-Member -InputObject $newPort -MemberType NoteProperty -Name MaxUserPort -Value $maxUserPort
	return $newPort
}

######################### Beginning of the main routine ##########################

# Store MaxUserPort for percentage used calculations
$tcpParams = Get-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\services\Tcpip\Parameters
$maxPorts = MaxNumOfTcpPorts($tcpParams)   # call function to return max # ports as per OS version
$tcpTimedWaitDelay = $($tcpParams | Select-Object TcpTimedWaitDelay).TcpTimedWaitDelay

if($tcpTimedWaitDelay -eq $Null)           #Value wasn't configured in registry
{
	$tcpTimedWaitDelay = 240               #Default Value if registry value doesn't exist
	Add-Member -InputObject $tcpParams -MemberType NoteProperty -Name TcpTimedWaitDelay -Value $tcpTimedWaitDelay  #fake reg value for output
}
# display current date and time
Write-Host -Object $(Get-Date)

# Display the MaxUserPort and TcpTimedWaitDelay settings in the registry if available
$tcpParams | Format-List MaxUserPort,TcpTimedWaitDelay

# collection of IP Address and port counts
[System.Collections.HashTable] $ports = New-Object System.Collections.HashTable

[int32] $intWait = 0

netstat -an |
Select-String "TCP\s+.+\:.+\s+(.+)\:(\d+)\s+(\w+)" |
ForEach-Object {
	$key = $_.matches[0].Groups[1].value      # use the IP address as hash key
	$Status = $_.matches[0].Groups[3].value   # Last group contains port status
	if("TIME_WAIT" -like $Status)
	{
		$intWait = 1                          # incr count
	}
	else
	{
		$intWait = 0                          # don't incr count
	}
	if(-not $ports.ContainsKey($key))         #IP Address not yet counted
	{
		$port = New-Port -IPAddress $key -PortsWaiting $intWait -MaxUserPort $maxPorts    #intialize new tracking object
		$ports.Add($key,$port)                #Add the tracking object to hashtable
	}
	else                                      #otherwise a tracking object exists for this IP
	{
		$port = $ports[$key]                  #retrieve the tracking object
		$port.PortsUsed ++                    # increment the port count (PortsUsed)
		$port.PortsWaiting += $intWait        # increment PortsWaiting if status is TIME_WAIT
	}
}

# Format-Table -InputObject $ports.Values -auto

$ports.Values |
Sort-Object -Property PortsUsed, PortsWaiting -Descending  |
Format-Table -Property IPAddress,PortsWaiting,
@{Name='%Waiting';Expression ={"{0:P}" -f $_.PercentWaiting};Alignment="Right"},
PortsUsed,
@{Name='%Used';Expression ={"{0:P}" -f $_.PercentUsed}; Alignment="Right"} -Auto

Remove-Variable -Name "ports"
Display port count per IP address

Leave a Reply

Your email address will not be published. Required fields are marked *