Posted On December 9, 2020

PowerShell: Get Ports to Process Connections / Associations

kimconnect 0 comments
blog.KimConnect.com >> Codes , Networking >> PowerShell: Get Ports to Process Connections / Associations

Current Iteration:

Here is a quick snippet to enable Network Engineers and Systems dudes to gather connection info on local or remote Windows.

# Sample Output

# Checking connections on port(s) 80 443 8080 8443...
# Checking connections on for process name(s): chrome...
# Process names have not been defined. Program now scans 7 processes...

# ProcessName  PID Protocol SourceEndPoint     DestinationEndpoint ConnectionStatus processOwner
# -----------  --- -------- --------------     ------------------- ---------------- ------------
# chrome      5896 TCP      10.10.10.500:51788 10.10.10.500:8080   ESTABLISHED      KIMCONNECT\rambo
# chrome      5896 TCP      10.10.10.500:51789 10.10.10.500:8080   ESTABLISHED      KIMCONNECT\rambo
# chrome      5896 TCP      10.10.10.500:51793 10.25.1.1800:443    ESTABLISHED      KIMCONNECT\rambo
# chrome      5896 TCP      10.10.10.500:51794 10.25.1.1800:443    ESTABLISHED      KIMCONNECT\rambo
# getProcessConnections.ps1
# version 0.0.3
#
# Description:
#   This script will connect to a list of Windows machines to collect processes and their ports utilizations
#   This iteration includes information on the process owner(s)
#   Program has been slightly optimized
#
# Requirements:
#   WinRM connectivity is expected toward the list of computer names

$computerNames="$env:computername"
$processNames='chrome'
$portNumbers=@()

function invokeGetProcessPorts{
    [cmdletbinding()]
    Param(
        [string[]]$computerNames=$env:computername,
        [string[]]$processNames=$null,
        [string[]]$portNumbers=$null
        )
    function getProcessConnections{
        [cmdletbinding()]
        Param(
            [parameter(ValueFromPipeLine=$True)][AllowEmptyCollection()][string[]]$processNames=$null,
            [parameter(ValueFromPipeLine=$True)][AllowEmptyCollection()][string[]]$portNumbers=$null
            )
        # Initialize variables    
        $results=@()
        $psVersionFeasible=$PSVersionTable.PSVersion.Major -ge 4
        $processes=if($processNames){
                write-host "Checking connections on for process name(s): $processNames..." 
                if($psVersionFeasible){
                        try{                
                            get-process $processNames -IncludeUserName # This is only available in PoSh 4.0+ 
                        }catch{
                            write-warning $_
                        }
                    }else{
                        get-process $processNames
                        }
            }else{
                if($psVersionFeasible){               
                    get-process -IncludeUserName
                }else{
                    get-process
                }
            }
        
        if($processes){
            write-host "Checking $($processes.count) processes..." -ForegroundColor Yellow
            # Collecting wmiobjects to be able to invoke .getowner() method
            $processObjects=if(!$psVersionFeasible){Get-WmiObject Win32_Process}else{$null}
            $netStat=if($portNumbers){
                    write-host "Checking connections on port(s) $portNumbers..."
                    netstat -ano|?{$_ -match "\:($($portNumbers -join '|'))\s"}
                }else{
                    write-host 'Port numbers were not defined. Scanning all ports...' -ForegroundColor Yellow
                    Netstat -ano|?{$_ -match "\d$"}
                }
            $previousPid=$previousOwner=$null
            write-verbose "Process ID:"
            foreach($process in $processes){            
                $processId=$process.ID
                write-verbose "$processId"
                $processName=$process.ProcessName
                $processOwner=if($processId -ne $previousPid){
                    $previousOwner=if($processObjects){
                            $processObjects|?{$_.ProcessId -eq $processId}|%{if($_.GetOwner().User){$_.GetOwner().Domain+"\"+$_.GetOwner().User}else{'unknown'}}|select -unique
                        }else{
                            $process.UserName
                        }
                    $previousOwner
                }else{
                    $previousOwner
                }
                $matchedLines = $netStat|findstr $processId
                write-host "Process Id $processId matched $($matchedLines.count) lines"
                foreach($matchedLine in $matchedLines){                    
                    $line = $matchedLine.Split('') | where{$_ -ne ""} # remove empty lines
                    $leftCount = $line[1].LastIndexOf(':')
                    $rightCount = $line[2].LastIndexOf(':')
                    $sourceEndpoint=$line[1].SubString(0,$leftCount)+':'+$line[1].SubString($leftCount+1,($line[1].Length-$leftCount-1))
                    $destinationEndpoint=$line[2].SubString(0,$rightCount)+':'+$line[2].SubString($rightCount+1,($line[2].Length-$rightCount-1))
                    $results += [PSCustomObject]@{              
                        ComputerName = $env:computername
                        ProcessName  = $processName
                        PID = $processId
                        Protocol = $line[0]
                        SourceEndPoint = $sourceEndpoint
                        DestinationEndpoint = $destinationEndpoint
                        #LocalAddress = $line[1].SubString(0,$leftCount)
                        #LocalPort = $line[1].SubString($leftCount+1,($line[1].Length-$leftCount-1))
                        #RemoteAddress = $line[2].SubString(0,$rightCount)
                        #RemotePort = $line[2].SubString($rightCount+1,($line[2].Length-$rightCount-1))
                        ConnectionStatus = $(if(!($line[3] -match '\d')){$line[3]}) # Checking if the connection contains any empty string.
                        processOwner=$processOwner
                    }
                }
                $previousPid=$processId
            }            
        if($results){
            return $results
            }elseif($processNames -and $portNumbers){
                write-host "$processNames not found on $portNumbers" -ForegroundColor Yellow
                return $null                
            }else{
                write-host "No processes matched." -ForegroundColor Yellow
                return $null
            }
        }else{
            write-host "No processes matched." -ForegroundColor Yellow
            return $null
        }
    }

    $results=@()
    foreach ($computerName in $computerNames){
        $session=New-PSSession -ComputerName $computerName
        if($session.state -eq 'Opened'){
            $result=invoke-command -ComputerName $computerName -scriptblock{
                param($importFunc,$x,$y)
                write-host "Executing function on $env:computername"
                [scriptblock]::create($importFunc).invoke($x,$y)
            } -args ${function:getProcessConnections},$processNames,$portNumbers
            if($result){
                $results+=$result
            }else{
                write-host "No matches on $computerName"
            }
            Remove-PSSession $session
        }else{
            write-warning "Unable to connect to $computername"
        }
    }
    return $results
}

$resultArray=invokeGetProcessPorts $computerNames $processNames $portNumbers
$resultArray|ft

Previous Iterations:

# getProcessConnections.ps1
# version 0.0.2
#
# Description:
#   This script will connect to a list of Windows machines to collect processes and their ports utilizations
#   This iteration includes information on the process owner(s)
#   Program needs to be further optimized
#
# Requirements:
#   WinRM connectivity is expected toward the list of computer names

$computerNames=$env:computername
$processNames='chrome'
$portNumbers=@(80,443,8080,8443)
function getProcessConnections{
    [cmdletbinding()]
    Param(
        [parameter(ValueFromPipeLine=$True)][AllowEmptyCollection()][string[]]$processNames=$null,
        [parameter(ValueFromPipeLine=$True)][AllowEmptyCollection()][string[]]$portNumbers=$null
        )
    # Initialize variables    
    $results = @()
    $netStat = if(!$portNumbers){
            write-host 'Port numbers were not defined. Program now scans all ports...' -ForegroundColor Yellow
            Netstat -ano
        }else{
            write-host "Checking connections on port(s) $portNumbers..."
            netstat -ano|?{$_ -match "\:($($portNumbers -join '|'))\s"}
        }
    $processes=if($processNames){
        write-host "Checking connections on for process name(s): $processNames..."         
            Get-Process $processNames
        }else{                
            get-process
        }

    if($processes){
        write-host "Process names have not been defined. Program now scans $($processes.count) processes..." -ForegroundColor Yellow
        foreach($process in $processes){
            $processOwner=Get-WmiObject Win32_Process -Filter "ProcessId='$($process.ID)'"|%{if($_.GetOwner().User){$_.GetOwner().Domain+"\"+$_.GetOwner().User}else{'unknown'}}|select -unique
            $matchedLines = $netStat|findstr $process.ID
            foreach($matchedLine in $matchedLines){                    
                $line = $matchedLine.Split('') | where{$_ -ne ""} # remove empty lines
                $leftCount = $line[1].LastIndexOf(':')
                $rightCount = $line[2].LastIndexOf(':')
                $sourceEndpoint=$line[1].SubString(0,$leftCount)+':'+$line[1].SubString($leftCount+1,($line[1].Length-$leftCount-1))
                $destinationEndpoint=$line[2].SubString(0,$rightCount)+':'+$line[2].SubString($rightCount+1,($line[2].Length-$rightCount-1))
                $results += [PSCustomObject]@{              
                    ProcessName  = $process.Name
                    PID = $process.ID
                    Protocol = $line[0]
                    SourceEndPoint = $sourceEndpoint
                    DestinationEndpoint = $destinationEndpoint
                    #LocalAddress = $line[1].SubString(0,$leftCount)
                    #LocalPort = $line[1].SubString($leftCount+1,($line[1].Length-$leftCount-1))
                    #RemoteAddress = $line[2].SubString(0,$rightCount)
                    #RemotePort = $line[2].SubString($rightCount+1,($line[2].Length-$rightCount-1))
                    ConnectionStatus = $(if(!($line[3] -match '\d')){$line[3]}) # Checking if the connection contains any empty string.
                    processOwner=$processOwner
                }
            }
        }            
    if($results){
        return $results|ft -AutoSize
    }elseif($processNames -and $portNumbers){
        write-host "$processNames not found on $portNumbers" -ForegroundColor Yellow
    }else{
        write-host "No processes matched." -ForegroundColor Yellow
    }
    }else{
        write-host "No processes matched." -ForegroundColor Yellow
        return $null
    }    
}

foreach ($computerName in $computerNames){
        invoke-command -ComputerName $computerName -scriptblock{
        param($importFunc,$x,$y)
        [scriptblock]::create($importFunc).invoke($x,$y)
    } -args ${function:getProcessConnections},$processNames,$portNumbers
}
# getProcessConnections.ps1
# version 0.0.1
# This function is expected to run on a Windows localhost session

function getProcessConnections{
    [cmdletbinding()]
    Param(
        [parameter(Mandatory=$False, ValueFromPipeLine=$True)][AllowEmptyCollection()]
        [string[]]$processNames=$null,
        [string[]]$portNumbers=$null
    )
    Begin{    
        $results = @()
        $netStat = if(!$portNumbers){
                write-host 'Port numbers were not defined. Program now scans all ports...' -ForegroundColor Yellow
                Netstat -ano
            }else{
                write-host "Checking connections on port(s) $portNumbers..."
                netstat -ano|?{$_ -match "\:($($portNumbers -join '|'))\s"}
            }
        $processes=if($processNames){
            write-host "Checking connections on for process name(s): $processNames..."         
                Get-Process $processNames
            }else{
                write-host 'A process name has not been defined. Program now scans all processes...' -ForegroundColor Yellow
                get-process
            }
    }Process{
        if($processes){
            foreach($process in $processes){
                $matchedPorts = $netStat | findstr $process.ID
                foreach($matchedPort in $matchedPorts){                    
                    $line = $matchedPort.Split('') | where{$_ -ne ""} # remove empty lines
                    $leftCount = $line[1].LastIndexOf(':')
                    $rightCount = $line[2].LastIndexOf(':')
                    $sourceEndpoint=$line[1].SubString(0,$leftCount)+':'+$line[1].SubString($leftCount+1,($line[1].Length-$leftCount-1))
                    $destinationEndpoint=$line[2].SubString(0,$rightCount)+':'+$line[2].SubString($rightCount+1,($line[2].Length-$rightCount-1))
                    $results += [PSCustomObject]@{              
                        ProcessName  = $process.Name
                        PID = $process.ID
                        Protocol = $line[0]
                        SourceEndPoint = $sourceEndpoint
                        DestinationEndpoint = $destinationEndpoint
                        #LocalAddress = $line[1].SubString(0,$leftCount)
                        #LocalPort = $line[1].SubString($leftCount+1,($line[1].Length-$leftCount-1))
                        #RemoteAddress = $line[2].SubString(0,$rightCount)
                        #RemotePort = $line[2].SubString($rightCount+1,($line[2].Length-$rightCount-1))
                        ConnectionStatus = $(if(!($line[3] -match '\d')){$line[3]}) # Checking if the connection contains any empty string.
                    }
                }
            }            
        return $results|ft -AutoSize
        }else{
            write-host "No processes matched." -ForegroundColor Yellow
            return $null
        }
    }
}

getProcessConnections -portNumbers 80,443
getProcessConnections -processNames chrome

Leave a Reply

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

Related Post

PowerShell: Benchmark Disk Speed

Contrary to previous iteration, this version returns an object with multiple properties describing statistical analysis…

WordPress Plugin to Customize How Posts are Displayed

A. Install the 'Display Posts' plugin B. Install the 'Code Snippets' plugin C. Add this…

PowerShell: Uninstalling an Application

$appname='Google Chrome' function uninstallApp($appName){ $alternativeMethod=$false try{ $app = Get-WmiObject -Class Win32_Product | Where-Object{$_.Name -eq $appName}…