Search code examples
powershellparsingwindows-10netstat

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

Solution

  • 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["