Thursday, June 21, 2012

Charting Procmon network output with .NET 4.0 and Powershell


Lots to work out in this post. Powershell v 3.0 CTP2 or Beta.  Procmon is Mark Russinovich's flagship tool for diagnosing Windows activity. It normally runs from the (admin) command prompt:

procmon /noconnect /nofilter /minimized /quiet

From Powershell admin prompt you can run thus:

start-process .\procmon.exe -arg '/LoadConfig JustNetwork.pmc' /quiet -verb runas -window hidden

whereupon a hidden procmon would run in the background capturing network traffic provided  that you have exported the configuration 'JustNetwok.pmc' to your path. You can create this filter and  export this configuration from the file menu:




There is no command line interface to procmon, however the GUI options can be found with 
'procmon /?'.
So we can create some powershell functions:

function p {start-process .\procmon.exe -arg '/LoadConfig JustNetwork.pmc',/quiet -verb runas -window minimized}
function q {start-process .\procmon.exe -arg /Terminate -verb runas}

Start the procmon filter: (e.g. function 'p' )
Now export the data from the interface to CSV format only (e.g. 'JustNetwork.csv')
Terminate procmon or stop the capture from the interface or from Powershell:  (e.g. function 'q')
Now import the data into an array:  [array[]]$n=import-csv .\JustNetwork.CSV
So that $n[0]:

Time of Day  : 8:40:40.7263831 PM
Process Name : svchost.exe
PID          : 484
Operation    : UDP Receive
Path         : ff02::1:2:dhcpv6-server -> rmfvpc:dhcpv6-client
Result       : SUCCESS
Detail       : Length: 72, seqnum: 0, connid: 0


$n[0..2]."Time of Day"
8:40:40.7263831 PM
8:40:40.8708796 PM
8:40:40.8709720 PM


$n[0..2].PID
484
4
4

Now choose two numerical  fields to chart making sure the X data is unique ('keys') and preferably sequential. Procmon's seven digit seconds work great!  Then create a hashtable suitable for Microsoft Charting in Powershell using MS Charting as a download or as it comes with .NET 4.0 Framework. Use Powershell's new hashtable array feature with the ordered attribute to do this:

[ordered]@{XKey=YValue}

foreach ($i in (0..($n.count - 1))) {$hashdata+=[ordered]@{$n[$i]."Time of Day"=$n[$i].PID}}


Your data looks like this:
($hashdata | more)[0..20]



Name                           Value
----                           -----
5:44:48.6806780 AM             1896
5:44:48.7189591 AM             4
5:44:48.7190397 AM             4
5:44:48.8205623 AM             1896
5:44:49.0389037 AM             1896
5:44:49.2649718 AM             1896
5:44:49.2650074 AM             1896
5:44:49.4831550 AM             4
5:44:49.4832392 AM             4
5:44:49.5346115 AM             1896
5:44:50.7088010 AM             1896
5:44:50.7088479 AM             1896
5:44:50.7890861 AM             1896
5:44:50.7891464 AM             1896
5:44:50.9011721 AM             1896
5:44:50.9012164 AM             1896
5:44:51.3591575 AM             944
5:44:51.3633674 AM             944



Source the function :  '. .\Chart-hashdata.ps1'
Now chart the hashtable
chart-hashdata point 500 500 "Process IDs" TIME PID



Object array data is important and faster to process, but I can not get it to chart:

$ArrayData=foreach ($i in (0..($n.count - 1))) {[ordered]@{$n[$i]."Time of Day"=$n[$i].Path.split('>')[1]}}

$ArrayData.gettype()


IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array


$ArrayData


Name                           Value
----                           -----
8:40:40.7263831 PM              rmfvpc:dhcpv6-client
8:40:40.8708796 PM              192.168.0.255:netbios-ns
8:40:40.8709720 PM              rmfvpc.rmfdevelopment.com:netbios-ns
8:40:41.6257380 PM              192.168.0.255:netbios-ns
8:40:41.6257937 PM              rmfvpc.rmfdevelopment.com:netbios-ns
8:40:42.3757645 PM              192.168.0.255:netbios-ns
8:40:42.3758202 PM              rmfvpc.rmfdevelopment.com:netbios-ns
8:40:44.0271291 PM              192.168.0.1:domain
8:40:44.0642094 PM              192.168.0.1:domain


$a=$ArrayData.Values | group | Sort -desc count | ft -auto Count,Name
$a


Count Name
----- ----
  144  RMFHOPE:microsoft-ds
   30  RMFHOPE:1029
   27  sea09s01-in-f21.1e100.net:https
   22  192.168.0.1:ssdp
   14  ec2-107-22-87-71.compute-1.amazonaws.com:ms-wbt-server
    6  RMFHOPE:epmap
    5  rmfvpc:dhcpv6-client
    3  rmfvpc.rmfdevelopment.com:netbios-ns
    3  224.0.0.252:netbios-ns
    3  239.255.255.250:netbios-ns
    3  192.168.0.255:netbios-ns
    3  192.168.0.1:netbios-ns
    3  224.0.0.252:llmnr
    2  sjc-not4.sjc.dropbox.com:http
    2  RMFHOPE:netbios-ns
    2  192.168.0.1:domain
    1  rmfvpc:65428


2 comments:

  1. Thanks! I am definitely going to use this.

    Also, I fixed the issue of not being able to run procmon from the command line. It allows you to specify a filter such as "Event Class,Is,Network,Include". Working on a way to change the filter on the fly, which would add a whole level of usefulness.

    Writeup/Script: nomanualrequired.blogspot.com/2013/04/automating-process-monitor.html

    ReplyDelete
  2. While very interesting, I think analyzing the time between send and the last receive would be more useful.

    Typically for database application we have the sequence
    TCP send -> n x TCP receive

    Analysing this would normally be something I would do in awk on a Unix/Linux system.

    It would be interesting being able to graph the times using your procedures.

    ReplyDelete