My PowerShell module PSNetStat contains the Get-NetStat function that offers features similar to the popular netstat.exe command. You can use it to analyze and display network connections in PowerShell.

During the lead-up to IronScripter at the 2018 DevOps + PowerShell Global Summit, there were several weekly competitions to prepare for the official competition. One such challenge was during Week 4 where the challenge asked the competitor to generate a PowerShell equivalent to the output of netstat.exe.

This was an interesting challenge for me, so I took a shot at it, and it resulted in me creating PSNetStat: a PowerShell module. PSNetStat went further than the original inquiry, and it recreated most of the functionality of netstat.exe using PowerShell.

Netstat.exe is a command-line utility that provides network statistics. It displays active and inactive network connections (both inbound and outbound) along with protocol statistics and connections. Windows introduced netstat to its ecosystem during the beginning of the Windows NT era. There are ports of the same application on Unix, Linux, macOS, Solaris, and BSD.

PSNetStat currently only works on Windows operating systems, but as time permits, I will also support PowerShell Core in the future. Now, let's take a look at the module layout:

PSNetStat PowerShell module folder structure

PSNetStat PowerShell module folder structure

When importing this module using the PSNetStat.psm1 file, it will traverse through both the Public and Private folders and export only the Public module members. You can see this in the script module file:

#requires -Version 2
#Get public and private function definition files.
$Public  = @( Get-ChildItem -Path $PSScriptRoot\Public\*.ps1 -Recurse -ErrorAction SilentlyContinue )
$Private = @( Get-ChildItem -Path $PSScriptRoot\Private\*.ps1 -Recurse -ErrorAction SilentlyContinue )

#Dot source the files
Foreach($import in @($Public + $Private))
        . $import.fullname
        Write-Error -Message "Failed to import function $($import.fullname): $_"

Export-ModuleMember -Function $Public.Basename

I'll give a quick shout-out to Warren Frame (a.k.a. PSCookieMonster). The idea of importing PowerShell modules this way originally came from him—at least from my perspective.

As you can see, we are looping through our folder and using the Export-ModuleMember cmdlet to allow only the functions in the Public folder that are visible or usable. The functions in the Private folder are intended for internal-module use only, and we should not use them directly.

The PSD1 or PowerShell module manifest file is a configuration definition file that allows you to specify requirements, dependencies, and much more. A manifest allows the module's writer to make sure the environment it is running on meets all the requirements necessary for it to work.

We can import this PowerShell Module using the built-in Import-Module cmdlet.

Import-Module .\PSNetStat.psm1 -Force

After importing the module, we can take a look at the available function by using the Get-Module cmdlet and viewing the exported commands (public functions).

(Get-Module -Name PSNetStat).ExportedCommands
PSNetStat ExportedCommands

PSNetStat ExportedCommands

As you can see in the screenshot above, the only public and exposable function is the Get-NetStat function. The other functions within the Private folder are not "naturally" exposed or usable.

Let's take a look at the Get-NetStat function. This is the one and only entry point to receive network statistics using this module.

The default behavior for Get-NetStat is that it will only show the active TCP connections.

Default output of Get NetStat

Default output of Get NetStat

	Function Get-NetStat
	        # Display all connections.  Default is Active TCP Connections

	        # Display a specific protocol.  Default is TCP & UDP
	        [ValidateSet('TCP', 'UDP')]

	    if ($ListeningProtocol)
	            'TCP'   { Get-ActiveTcpListeners | Write-Output }
	            'UDP'   { Get-ActiveUdpListeners | Write-Output }
	            default { Get-ActiveTcpListeners | Write-Output
	                      Get-ActiveUdpListeners | Write-Output }
	    elseif ($AllConnections.IsPresent)
	        Get-ActiveTcpListeners | Write-Output
	        Get-ActiveUdpListeners | Write-Output
	        Get-ActiveTcpConnections | Write-Output
	        Get-ActiveTcpConnections | Write-Output

Below is a screenshot of both netstat.exe's output using the -p TCP command-line option vs. the default output of Get-NetStat:

Netstat p TCP and the default behavior of the Get NetStat PowerShell module

Netstat p TCP and the default behavior of the Get NetStat PowerShell module

If you would like to see all connections, you can pass in a switch of -AllConnections. By doing this, you will get all active TCP and UDP listeners and all active TCP connections. This option is the most robust option, and it will return all available information.

Get NetStat with the AllConnections switch

Get NetStat with the AllConnections switch

Using the -AllConnections switch is similar to when you run:

netstat -a

The last option you have is that you can select whether you want to see only TCP or UDP connections. If you want to see all connections but only the TCP ones then you would use:

Get-NetStat -AllConnections -ListeningProtocol TCP

Now, let's dive into the fun part! Let's take a look at one of those private functions I mentioned earlier. Here is a look at Get-ActiveTcpConnections.ps1:

function Get-ActiveTcpConnections
    $networkObject = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
    $networkObject.GetActiveTcpConnections() | ForEach-Object {
        $props = [PSCustomObject]@{
            Protocol          = 'TCP'
            'Local Address'   = $_.LocalEndPoint 
            'Foreign Address' = Convert-NetStatRemoteEndpoint -Address $_.RemoteEndPoint.get_address().IPAddressToString -Port $_.RemoteEndPoint.get_Port()
            State             = $_.State
        Write-Output $props

Get-ActiveTcpConnections uses the System.Net.NetworkInformation namespace to retrieve information about all active TCP connections. We loop through all active connections and create our PSCustomObject. Part of the properties of this object also uses another private function called Convert-NetStatRemoteEndpoint to determine whether it is a local address. If it is a local address, we replace either or with the local machine's host name. If it is not a local address, we keep it as it is and return the new formatted string and add it to our PSCustomObject under the Foreign Address property.

The returned objects from Get-ActiveTcpConnections, Get-ActiveTcpListeners, and Get-ActiveUdpListeners are private functions. It calls each of these private functions depending on which switches we pass to Get-NetStat. It then returns and displays the result back to the console.

Subscribe to 4sysops newsletter!

My PSNetStat PowerShell module is not exactly the same as the built-in netstat.exe application, since netstat.exe uses unmanaged code and accesses lower-level WIN_API classes to get additional information from GetExtendedTcpTable and GetExtendedUdpTable. The .NET framework doesn't natively expose these classes, so in order to access them, you would need to implement a new Add-Type or C#/C++ DLL.

  1. Josh,

    This module looks awesome. Can't wait to to fire it up and try it out. Great work!

    • Author

      Mike, thanks!  I would love to hear your feedback; and I'm always accepting Pull Requests on GitHub!

  2. Anthony Bushong 3 years ago

    This is great! Just yesterday,  I was looking for a PS module to do exactly this! Can't wait to try it out. Thanks for sharing!

    • Author

      Anthony, that's great to hear!  Please let me know if you encounter any issues or any positives as well!

  3. Scott L. 3 years ago

    Thanks Josh for the post, I will test drive this module myself.

  4. Imraz 2 years ago

    Hello, is there a re-req article to this one? I cant get Get-ActiveTcpConnections.ps1: to work, erroring out on:

    Convert-NetStatRemoteEndpoint : The term 'Convert-NetStatRemoteEndpoint' is not recognized as the name of a cmdlet, function, script file, or operable program.


    which makes sense because I never created any such function anywhere. I'm trying to create something that shows tcp connections with the state of Time_wait, Close_wait and listening and to output the info to a file or OGV with Time stamps, I want it to run for maybe 10 minutes. Not sure if this is doable, but want to get this function to work.

Leave a reply

Please enclose code in pre tags

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


© 4sysops 2006 - 2021


Please ask IT administration questions in the forums. Any other messages are welcome.


Log in with your credentials


Forgot your details?

Create Account