Parsing NetStat Information with PowerShell 5


Summary: Ed Wilson, Microsoft Scripting Guy, talks about parsing output from NetStat with Windows PowerShell 5.0.

Hey, Scripting Guy! Question Hey, Scripting Guy! I need a good way to parse output from the NetStat command. I use it all the time, but it ends up requiring me to spend a lot of time looking through stuff. I am not sure if the command itself has a filter language or what, but I really need to be able to parse on the fly.

I have even gone so far as run the command, copy it to the clipboard, paste it into Notepad, and then go through the Notepad file adding characters so I could import it into Excel and filter the output. But obviously, that is a lot of work. I really need to be able to see stuff like what connections are open, closed, and suspended. Can you help me?

—JK

Hey, Scripting Guy! Answer Hello JK,

Microsoft Scripting Guy, Ed Wilson, is here. It hasn’t started raining yet, but I am sure it will. I mean, summer in central Florida? There are two things one can count on: an afternoon thunder storm and humidity. Lots and lots of humidity. I am not sure what people did before air conditioning around here. Maybe they lived in St. Augustine where they could go to the beach every day.

Anyway, just like I can count on a summer thunderstorm in central Florida, I can also count on the fact that I am going to have to parse text at some point. Luckily that task just took a giant leap towards simplicity with the new ConvertFrom-String cmdlet in Windows PowerShell 5.0.

JK, parsing output from NetStat just got a whole lot easier. In the past, I have written complicated scripts to parse the output from NetStat. I mean it was nearly 20 or so lines long, and it took me a couple of days to accomplish it—but in the end, I was able to output objects that permitted me to filter my output. It was worth it. But as of Windows PowerShell 5.0, the script is completely obsolete.

Capture the output

The first thing I want to do is to capture the output from NetStat. I like to store the results from the command into a variable because the output from NetStat is always a bit slow appearing. By capturing the output into a variable, I can effectively work offline. This command is shown here:

$a = netstat

When I look at the output from the information stored in my variable, I can see that there are a couple of lines that I do not need:

PS C:\> $a

Active Connections

  Proto  Local Address          Foreign Address        State

What I want is an easy way to skip the first few lines, but keep the remainder of the output. Luckily, I know exactly how many lines are in the variable—it is $a.count. So, I create a range that skips the first few lines, and continues to the end of my data. This is shown here:

PS C:\> $a[3..$a.count]

  Proto  Local Address          Foreign Address        State

  TCP    192.168.0.2:56798      bn1wns2011304:https    ESTABLISHED

  TCP    192.168.0.2:56852      bn1wns1011219:https    ESTABLISHED

  TCP    192.168.0.2:57076      a184-27-27-179:https   ESTABLISHED

  TCP    192.168.0.2:57080      a184-29-178-13:https   CLOSE_WAIT

<truncated>

Now I need to convert the output to objects by using the ConvertFrom-String cmdlet. By default, it will use spaces to create a property on the new object. This is great, because my output from NetStat is delimited by spaces. But, when I look at my output, I see that there must be a leading space, so P1 is empty:

PS C:\> $a[3..$a.count] | ConvertFrom-String

P1 :

P2 : Proto

P3 : Local

P4 : Address

P5 : Foreign

P6 : Address

P7 : State

P1 :

P2 : TCP

P3 : 192.168.0.2:56798

P4 : bn1wns2011304:https

P5 : ESTABLISHED

P1 :

P2 : TCP

P3 : 192.168.0.2:56852

P4 : bn1wns1011219:https

P5 : ESTABLISHED

<truncated>

I simply use Select-Object to select properties P2, P3, P4, and P5:

$a[3..$a.count] | ConvertFrom-String | select p2,p3,p4,p5

The output from the command is shown here:

Image of command output

Now I can easily filter by any property value I want. For example, I can filter the output for connections that are established. As you can see here, I add where P5 –eq ‘established’:

$a[3..$a.count] | ConvertFrom-String | select p2,p3,p4,p5 | where p5 -eq 'established'

The command and its output are shown here:

Image of command output

I can look for things related to mail:

$a[3..$a.count] | ConvertFrom-String | select p2,p3,p4,p5 | where p4 -match 'mail'

...or a specific part of an IP address, such as this command that finds IP addresses that begin with the number 23:

$a[3..$a.count] | ConvertFrom-String | select p2,p3,p4,p5 | where p4 -match '^23'

When I have my output from NetStat converted into true objects, I can use the entire power of Windows PowerShell to search through the objects and find exactly what I need—and I can do it all in a series of one-liners. That truly is the power of PowerShell.

JK, that is all there is to using ConvertFrom-String to help parse NetStat output. Join me tomorrow when I will talk about more way cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Comments (3)

  1. I would do it this way:

    $a = netstat
    $a.trim() | select -Skip 4 | ConvertFrom-String -PropertyNames Protocol,LocalAddress,RemoteAddress,State

    I call the trim() function on the $a to trim all the string so we get rid of whitespaces in the beginning of the string and this eliminates the "blank" P1 you have. Then I use the -PropertyNames to give the resulting objects some usable property names instead
    of P1-P5.

  2. Mine needs improvement says:

    (netstat -ano).trim() | select -Skip 4 | ConvertFrom-String -PropertyNames Protocol,LocalAddress,RemoteAddress,State,Process | % { $_ | Add-Member -MemberType NoteProperty -Name SourcePort -Value $_.LocalAddress.SubString($_.LocalAddress.LastIndexOf(":")+1);
    $_ |Add-Member -MemberType NoteProperty -Name SourceIP -Value $_.LocalAddress.SubString(0,$_.LocalAddress.LastIndexOf(":")); $_ | Add-Member -MemberType NoteProperty -Name RemotePort -Value $_.RemoteAddress.SubString($_.RemoteAddress.LastIndexOf(":")+1); $_
    |Add-Member -MemberType NoteProperty -Name RemoteIP -Value $_.RemoteAddress.SubString(0,$_.RemoteAddress.LastIndexOf(":")); $_} |ft

  3. KERR says:

    Any way to do this in PS v4

Skip to main content