List All Open TCP Ports and Which Processes That are Listening to Them

Let’s face it, sometimes we sit there staring at the computer screen wondering; “I wonder which ports i have open on my system? And which of my applications are using them?”
Well, maybe it’s just us..
But have you ever wanted to know which applications are listening on the computer’s open ports, then look no further.
With some PowerShell magic we can get a nice overview, either it’s for entertaining purposes, security purposes, or just because we can purpose.
(Not sure what TCP is? We got you covered in simple terms!)

First we need to gather all the TCP connections that are currently in a listening state.
Then we need to select the desired properties we want which in this case it’s “ProcessID” and “ProcessName“. And finally before we can dump the output to the terminal window we need to sort it to “LocalPort” since we only want to see info regarding our own machine and not the port of the receiving end.
This should have the PowerShell script look like this:

$tcpConnections = Get-NetTCPConnection -State Listen
$selectedConnections = $tcpConnections | Select-Object -Property LocalPort, State, 
    @{name='ProcessID'; expression={
        $process = Get-Process -Id $_.OwningProcess
        $process.ID
    }}, 
    @{name='ProcessName'; expression={
        $process = Get-Process -Id $_.OwningProcess
        $process.Path
    }}

$sortedConnections = $selectedConnections | Sort-Object LocalPort
$sortedConnections

We can also make this code into a simpler “One-Liner” code like this:

Get-NetTCPConnection -State Listen | Select-Object -Property LocalPort, State, @{name='ProcessID';expression={(Get-Process -Id $_.OwningProcess). ID}}, @{name='ProcessName';expression={(Get-Process -Id $_.OwningProcess). Path}} | Sort-Object LocalPort

As we can see from the output in the terminal it lists only what we asked for.
We can also see several ports that are being listened to, but have no software linked to it. These ports are being listened to by either the System, or a service running on the computer.
If we include these too in our PowerShell script it starts to get a bit overwhelming with information, but to give those of you who are curious a chance, we can add them in as well. In the script below, we just added the “Service name” and “SystemProcess” just like we did with “ProcessName”, and “ProcessID” and it should look like this:

$tcpConnections = Get-NetTCPConnection -State Listen
$selectedConnections = $tcpConnections | Select-Object -Property LocalPort, State,
    @{name='ProcessID'; expression={
        $process = Get-Process -Id $_.OwningProcess
        $process.ID
    }},
    @{name='ProcessName'; expression={
        $process = Get-Process -Id $_.OwningProcess
        $process.ProcessName
    }},
    @{name='ServiceName'; expression={
        $service = Get-Service | Where-Object { $_.Id -eq $_.OwningProcess }
        if ($service) {
            $service.Name
        } else {
            'N/A'
        }
    }},
    @{name='SystemProcess'; expression={
        if ($_.OwningProcess -lt 1024) {
            'Yes'
        } else {
            'No'
        }
    }}

$sortedConnections = $selectedConnections | Sort-Object LocalPort
$sortedConnections

This output will fill in all the missing fields from our previous script, and drop a ton of information on us. It’s a good thing we sorted it out a bit and maybe it’s possible to sort it out even more, but that would be for another time.

Let’s get all fancy with GUI

To Achieve this we need to give the code a little makeover.
Alright, lets get a bit fancy here. Lets add some GUI to the code and have it appear as a spreadsheet box on the screen. To do this we need to bring some more stuff to the table.
First we need to add the necessary .NET assemblies to use Windows Forms.
We also need to have the script create a Windows Form and display it as “DataGridView” which will be the spreadsheet. Feel free to play with the height and width on both the Windows Form and the DataGridView size to make it fit your desired output.

Now we need to put it all together with the code in the beginning of this post, create the GUI using “form” and “datagridview”, and the final script should look like this:

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$connections = Get-NetTCPConnection -State Listen | Select-Object -Property LocalPort, State, 
    @{name='ProcessID';expression={(Get-Process -Id $_.OwningProcess). ID}}, 
    @{name='ProcessName';expression={(Get-Process -Id $_.OwningProcess). Path}} | Sort-Object LocalPort

$form = New-Object System.Windows.Forms.Form
$form.Text = "Listening Ports"
$form.Size = New-Object System.Drawing.Size(800,600)
$form.StartPosition = "CenterScreen"

$datagridview = New-Object System.Windows.Forms.DataGridView
$datagridview.Size = New-Object System.Drawing.Size(780, 550)
$datagridview.Location = New-Object System.Drawing.Point(10,10)
$datagridview.AutoSizeColumnsMode = "Fill"

$dataTable = New-Object System.Data.DataTable
$dataTable.Columns.Add("Port") | Out-Null
$dataTable.Columns.Add("State") | Out-Null
$dataTable.Columns.Add("ProcessID") | Out-Null
$dataTable.Columns.Add("Application") | Out-Null

foreach ($connection in $connections) {
    $row = $dataTable.NewRow()
    $row["Port"] = $connection.LocalPort
    $row["State"] = $connection.State
    $row["Application"] = $connection.ProcessName
    $row["ProcessID"] = $connection.ProcessID
    $dataTable.Rows.Add($row)
}

$datagridview.DataSource = $dataTable
$form.Controls.Add($datagridview)
[void]$form.ShowDialog()

We hope this was helpful, and feel free to tweak the code to suit your need.
As always; Stay curious, and learn something new every day!