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 to an object.
A snippet of the output 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 whitespace (or not whitespace) 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 being pushed into a different 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 the 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 as shown following:
$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>
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