Flatten netstat command output in powershell

I am attempting to use netstat -bano and collect the output in PowerShell for some very specific reporting requirements.

I have working regex that should be able to parse this output no problem, but since the output appears on multiple lines, the regex isn't being processed correctly

here's a screenshot of how it comes out of netstat

sample output

desired output is something like this (all on one line):

TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       1092  RpcSs [svchost.exe]
TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4     Can not obtain ownership information
TCP    0.0.0.0:623            0.0.0.0:0              LISTENING       7404  [LMS.exe]
TCP    0.0.0.0:3389           0.0.0.0:0              LISTENING       1224  TermService [svchost.exe]

the use of tools outside of Windows isn't possible, so I'm confined to common tools.

Using Get-Process matching on PID also won't work, as it hides sub process information under svchost and lsass. netstat with a -b is perfect because it shows both svchost.exe and the process that utilizes the port

I've scoured the internet to find a viable solution but most end in a different resolution

EDIT**here is my final script using input from you guys

$data = (netstat -bano |select -skip 4 | Out-String) -replace '(?m)^  (TCP|UDP)', '$1' -replace '\r?\n\s+([^\[])', "`t`$1" -replace '\r?\n\s+\[', "`t[" -split "`n"

[regex]$regex = '(?<protocol>TCP|UDP)\s+(?<address>\d+.\d+.\d+.\d+|\[::\]|\[::1\]):(?<port>\d+).+(?<state>LISTENING|\*:\*)\s+(?<pid>\d+)\s+(?<service>Can not obtain ownership information|\[\w+.exe\]|\w+\s+\[\w+.exe\])'

$output = @()

$data | foreach {
    $_ -match $regex

    $outputobj = @{
        protocol = [string]$matches.protocol
        address = [string]$matches.address -replace '\[::\]','[..]' -replace '\[::1\]','[..1]'
        port = [int]$matches.port
        state = [string]$matches.state -replace "\*:\*",'NA'
        pid = [int]$matches.pid
        service = ([string]$matches.service -replace 'Can not obtain ownership information','[System' -split '.*\[')[1] -replace '\]',''
        subservice = ([string]$matches.service  -replace 'Can not obtain ownership information','' -split '\[.*\]')[0]
    }
    $output += New-Object -TypeName PSobject -Property $outputobj
}
$output |select address,port,protocol,pid,state,service,subservice
728x90

2 Answers Flatten netstat command output in powershell

You can join the output of netstat so that it becomes one large multi-line string, then split it on lines that start with whitespace followed by TCP or UDP, followed by an IP address (to remove false positives of an application having a name of 'TCP tracker' or something). Then trim any whitespace from the beginning or end of the line, replace anywhere that there's two or more spaces with a comma, and push the results to ConvertFrom-Csv to create objects. From that you could filter, group, or just simply pipe to Format-Table to see the results.

$Netstat = (netstat -bano | Select -skip 2) -join "`n" -split "(?= [TU][CD]P\s+(?:\d+\.|\[\w*:\w*:))" | 
    ForEach-Object {$_.trim() -replace "`n",' ' -replace '\s{2,}',','} |
    ConvertFrom-Csv
# Filter the results for TCP connections and pipe the results to Format-Table
$Netstat | Where {$_.Proto -eq 'TCP'} | Format-Table

2 weeks ago

I would probably do something like this:

  1. mangle the output into a single string:

    netstat -bano | Out-String
    
  2. remove indention of the lines beginning with UDP or TCP to make them distinguishable from the other lines:

    -replace '(?m)^  (TCP|UDP)', '$1'
    
  3. join all indented lines that don't begin with a square bracket to the line preceding them:

    -replace '\r?\n\s+([^\[])', "`t`$1"
    
  4. join all indented lines that do begin with a square bracket to the line preceding them:

    -replace '\r?\n\s+\[', "`t["
    

Complete statement:

(netstat -bano | Out-String) -replace '(?m)^  (TCP|UDP)', '$1' -replace '\r?\n\s+([^\[])', "`t`$1" -replace '\r?\n\s+\[', "`t["

2 weeks ago