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.