A Better NetStat (Part 3)

by Jan 19, 2021

In the previous tip we introduced the Get-NetTCPConnection cmdlet as a better alternative to the network utility netstat.exe on Windows systems, and with a couple of tricks, you can even resolve IP addresses and process IDs. However, this slows down the command considerably because DNS lookup may take time, especially when it runs into network time outs.

Let’s examine how the new PowerShell 7 parallel processing capabilities can speed up things.

Below is the original code with traditional sequential processing that dumps all connections to port 443 and resolves host names and processes (slow):

$Process = @{
    Name='Process'
    Expression={
        # return process path
        (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Path
       
        }
}

$HostName = @{
    Name='Host'
    Expression={
        $remoteHost = $_.RemoteAddress
        try { 
            # try to resolve IP address
            [Net.Dns]::GetHostEntry($remoteHost).HostName
        } catch {
            # if that fails, return IP anyway
            $remoteHost
        }
    }
}

# get all connections to port 443 (HTTPS)
Get-NetTCPConnection -RemotePort 443 -State Established | 
  # where there is a remote address
  Where-Object RemoteAddress |
  # and resolve IP and Process ID
  Select-Object -Property $HostName, OwningProcess, $Process 

This is an approach utilizing the new “parallel loops” functionality in PowerShell 7 (fast):

# get all connections to port 443 (HTTPS)
Get-NetTCPConnection -RemotePort 443 -State Established | 
  # where there is a remote address
  Where-Object RemoteAddress |
  # start parallel processing here
  # create a loop that runs with 80 consecutive threads
  ForEach-Object -ThrottleLimit 80 -Parallel {
      # $_ now represents one of the results emitted
      # by Get-NetTCPConnection
      $remoteHost = $_.RemoteAddress
      # DNS resolution occurs now in separate threads
      # at the same time
      $hostname = try { 
                    # try to resolve IP address
                    [Net.Dns]::GetHostEntry($remoteHost).HostName
                  } catch {
                    # if that fails, return IP anyway
                    $remoteHost
                  }
      # compose the calculated information into one object
      [PSCustomObject]@{
        HostName = $hostname
        OwningProcess = $_.OwningProcess
        Process = (Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Path
      }
  } 

As you see, the second approach is much faster than before, and a good use case for the new “parallel loops” in PowerShell 7.

However, on the down side the code is now even less compatible and runs on Windows systems only, and in PowerShell 7 only. In our upcoming last part of this series, we’ll show a solution that is even simpler and runs cross-platform on all versions of PowerShell.


Twitter This Tip! ReTweet this Tip!