Public/Network/Get-LocalPort.ps1
function Get-LocalPort { <# .SYNOPSIS This parses the native netstat.exe's output using the command line "netstat -anb" to find all of the network ports in use on a local machine and all associated processes and services .NOTES Created on: 2/15/2015 Created by: Adam Bertram Filename: Get-LocalPort.ps1 .EXAMPLE PS> Get-LocalPort.ps1 This example will find all network ports in uses on the local computer with associated processes and services .EXAMPLE PS> Get-LocalPort.ps1 | Where-Object {$_.ProcessOwner -eq 'svchost.exe'} This example will find all network ports in use on the local computer that were opened by the svchost.exe process. .EXAMPLE PS> Get-LocalPort.ps1 | Where-Object {$_.IPVersion -eq 'IPv4'} This example will find all network ports in use on the local computer using IPv4 only. #> [CmdletBinding()] param () begin { #Requires -Version 3 Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' } process { try { ## Capture the output of the native netstat.exe utility ## Remove the top row from the result and trim off any leading or trailing spaces from each line ## Replace all instances of more than 1 space with a pipe symbol. This allows easier parsing of ## the fields $Netstat = (netstat -anb | Where-Object { $_ -and ($_ -ne 'Active Connections') }).Trim() | Select-Object -Skip 1 | ForEach-Object { $_ -replace '\s{2,}', '|' } $i = 0 foreach ($Line in $Netstat) { ## Create the hashtable to conver to object later $Out = @{ 'Protocol' = '' 'State' = '' 'IPVersion' = '' 'LocalAddress' = '' 'LocalPort' = '' 'RemoteAddress' = '' 'RemotePort' = '' 'ProcessOwner' = '' 'Service' = '' } ## If the line is a port if ($Line -cmatch '^[A-Z]{3}\|') { $Cols = $Line.Split('|') $Out.Protocol = $Cols[0] ## Some ports don't have a state. If they do, there's always 4 fields in the line if ($Cols.Count -eq 4) { $Out.State = $Cols[3] } ## All port lines that start with a [ are IPv6 if ($Cols[1].StartsWith('[')) { $Out.IPVersion = 'IPv6' $Out.LocalAddress = $Cols[1].Split(']')[0].TrimStart('[') $Out.LocalPort = $Cols[1].Split(']')[1].TrimStart(':') if ($Cols[2] -eq '*:*') { $Out.RemoteAddress = '*' $Out.RemotePort = '*' } else { $Out.RemoteAddress = $Cols[2].Split(']')[0].TrimStart('[') $Out.RemotePort = $Cols[2].Split(']')[1].TrimStart(':') } } else { $Out.IPVersion = 'IPv4' $Out.LocalAddress = $Cols[1].Split(':')[0] $Out.LocalPort = $Cols[1].Split(':')[1] $Out.RemoteAddress = $Cols[2].Split(':')[0] $Out.RemotePort = $Cols[2].Split(':')[1] } ## Because the process owner and service are on separate lines than the port line and the number of lines between them is variable ## this craziness was necessary. This line starts parsing the netstat output at the current port line and searches for all ## lines after that that are NOT a port line and finds the first one. This is how many lines there are until the next port ## is defined. $LinesUntilNextPortNum = ($Netstat | Select-Object -Skip $i | Select-String -Pattern '^[A-Z]{3}\|' -NotMatch | Select-Object -First 1).LineNumber ## Add the current line to the number of lines until the next port definition to find the associated process owner and service name $NextPortLineNum = $i + $LinesUntilNextPortNum ## This would contain the process owner and service name $PortAttribs = $Netstat[($i + 1)..$NextPortLineNum] ## The process owner is always enclosed in brackets of, if it can't find the owner, starts with 'Can' $Out.ProcessOwner = $PortAttribs -match '^\[.*\.exe\]|Can' if ($Out.ProcessOwner) { ## Get rid of the brackets and pick the first index because this is an array $Out.ProcessOwner = ($Out.ProcessOwner -replace '\[|\]', '')[0] } ## A service is always a combination of multiple word characters at the start of the line if ($PortAttribs -match '^\w+$') { $Out.Service = ($PortAttribs -match '^\w+$')[0] } [pscustomobject]$Out } ## Keep the counter $i++ } } catch { Write-Error "Error: $($_.Exception.Message) - Line Number: $($_.InvocationInfo.ScriptLineNumber)" } } } |