The netstat command produces tab-delimited, fixed-width tables. The following example converts the active connections that list active TCP connections, as well as listening TCP and UDP ports, into an object.
A snippet of the output that the example is intended to parse is shown in the following code:
PS> netstat -ano
Active Connections
Proto Local Address Foreign Address State PID
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 124
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:5357 0.0.0.0:0 LISTENING 4
When handling text such as this, a pattern based on white space (or not white space) can be used:
^s*S+s+S+
For each column, the following expression with a named group is created:
(?<ColumnName>S+)s+
The trailing s+ is omitted for the last column (PID):
^s*(?<Protocol>S+)s+(?<LocalAddress>S+)s+(?<ForeignAddress>S+)s+(?<State>S+)s+(?<PID>d+)$
The expression is long, but incredibly repetitive. The repetition is desirable in this case, where each column value is pushed into a differently named group.
The expression can be applied using Where-Object:
$regex = '^s*(?<Protocol>S+)s+(?<LocalAddress>S+)s+(?<ForeignAddress>S+)s+(?<State>S+)s+(?<PID>d+)$' netstat -ano | Where-Object { $_ -match $regex } | ForEach-Object { $matches.Remove(0) [PSCustomObject]$matches }
Unfortunately, the output from this command will be missing information about UDP ports. The regular expression makes having a value in the state column mandatory. Marking this group as optional will add UDP connection information to the output:
(State>S+)?
Inserting it back into the regular expression is achieved as follows:
$regex = '^s*(?<Protocol>S+)s+(?<LocalAddress>S+)s+(?<ForeignAddress>S+)s+(?<State>S+)?s+(?<PID>d+)$' netstat -ano | Where-Object { $_ -match $regex } | ForEach-Object { $matches.Remove(0) [PSCustomObject]$matches }
Finally, if it is desirable to return the fields in the same order as netstat does, Select-Object may be used:
PS>$regex = '^s*(?<Protocol>S+)s+(?<LocalAddress>S+)s+(?<ForeignAddress>S+)s+(?<State>S+)s+(?<PID>d+)$'
PS> netstat -ano | Where-Object { $_ -match $regex } | ForEach-Object {
$matches.Remove(0)
[PSCustomObject]$matches
} | Select-Object Protocol, LocalAddress, ForeignAddress, State, PID |
Format-Table
Protocol LocalAddress ForeignAddress State PID
-------- ------------ -------------- ----- ---
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING 124
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING 4
TCP 0.0.0.0:5357 0.0.0.0:0 LISTENING 4