Monday, February 23, 2009

Teaching myself debugging...some random notes:

There are no locals or watch windows in the CTP2  v3 ISE. They are sorely needed.  However, there is a plethora of debugging facilities in Powershell. Today's post is about my morning exploration  of such facilities. I have a function List-TCPConnections that works fine with one argument but doesn't work with multiple pipeline values.  This param: [ValueFromPipeline] gives me a "load assembly" error message and I am not ready to debug that right now ;-) .  I have a cmd.exe test script to give myself connection states: for /l %i in (1000,100,10000) do wget %i.com.  I run through TCP Connection States like this: '0..11 | %{List-TCPConnections $_}'

Under such test, the function below works as expected, pumping out connection states, IP addresses to console and (classic) EventLog:
function global:List-TCPEstablished {do {List-TCPConnections 5} while (1)}

This  (pipeline function) does not work :
function global:List-TCPAllStates {do {0..11 | %{List-TCPConnections $_}} while (1)}  

Originally, I tried some simple 'print debug' type strategies with "get-variable" (gv) and  "out-gridview". But the compound variables do not Invoke() (for me)  in "out-gridview" so these strategies weren't helping. 

   (gv -s 0)| out-gridview ## scope for everything
   (gv -s 1)| out-gridview ## one scope up

   ## Just what the script gives subtracted from everything
    compare-object (gv -s script) (gv -s 0) | out-gridview

Along the same lines, I thought I would be more tricky and pump out  variable arrays I wanted to watch  as needed: 

    $local_out=
    "last_netblock",
    "netblock",
    "State" 

    $dbg = $local_out | %{gv ($_)}; $dbg | out-gridview

That still wasn't helpful for the above reasons. Below, the trace command dumps lots of information, but still doesn't help me with logic errors:

trace-command -name metadata,parameterbinding,cmdlet -option ExecutionFlow,data,errors {do {0..11 | %{List-TCPConnections $_};sleep -s 5} while (1)}-pshost

Using a script block at the start of my Begin{} function and calling it as needed  was most useful at this point.

## Debug Print Script Block
    $Global:locals_out=
    {
    $State
    $last_netblock
    write .
    $netblock
    }

 ## Debug
    write $Locals_out.Invoke()

to be continued...

Wednesday, February 18, 2009

Three of the four last posts have resulted in a considerable speed up of my Powershell learning curve. In my February 6th post , I created a (not so) simple script to log all new Established TCP Connections.  'Compare-Object' was very useful in finding the diff between one netblock and the last. In my February 12th post, I worked through how to send those Established TCP Connections to the (classic) Event Viewer.  I then spent quite a bit of time trying to build a script that iterated all TCPStates past the current TCP Connection diff in an attempt to send all TCP State Connections to the Event Log.  I spent a lot of time failing to create such an iteration. (Update February 25): Eventually, I did create a function(s) which will log select TCP Connection States. It is posted here: http://www.rmfdevelopment.com/PowerShell_Scripts/List-TCPConnections_Advanced.ps1
 There are a ton of issues for me to work out with Powershell involving .NET overloads, Functions Types, Iteration, Parameters....But the foreach-object can be used in a block to process an  array line by line. Very simple and straightforward:
       $global:c = compare-object -referenceobject $State_netblock -differenceobject $State_last_netblock
                    
       if ($c -eq $null){}
       elseif($c.SideIndicator -eq "<=" )
          {$C |
                foreach-object -process{                                    
                $LocalAddress = $_.InputObject.LocalEndPoint.Address
                $RemoteAddress = $_.InputObject.RemoteEndPoint.Address           
                $LocalPort = $_.InputObject.LocalEndPoint.Port
                $RemotePort = $_.InputObject.RemoteEndPoint.Port
                $TCP_State = $TCPState[$State]
                $name = [System.Net.DNS]::Resolve("$RemoteAddress")
                $name_canon = $name.hostname
                write "$TimeNow $RemoteAddress $name_canon : $RemotePort $TCP_State"
                $EventLog.Source = "$name_canon" 
                $EventLog.WriteEntry("$LocalAddress $TCP_State connection to $RemoteAddress($name_canon) from Local Port: $LocalPort to Remote Port: $RemotePort",$infoevent,$RemotePort,$State) 

                } 
           }


Update on event log queries for the event log generated by the above script:

Source
$Source_8NetUnique = get-eventlog -log EstablishedTCPConnections  | ?{$_.Source -match "^8\."} | sort-object -property Source -unique
$SourceNetUnique = get-eventlog -log EstablishedTCPConnections  | ?{$_.Source -match "^*"} | sort-object -property Source -unique
$SourceNetUniqueGroupBy = get-eventlog -log EstablishedTCPConnections  | ?{$_.Source -match "^*"} | group-object -property Source | Sort-object -property count -descending
Function Get-NetName ($CountNetName) { get-eventlog -log EstablishedTCPConnections  | ?{$_.Source -match "^$CountNetName"} |  group-object -property Source | Sort-object -property count -descending}
foreach($i in (gc alpha.txt)){get-netname $i}
Port
$Port80 = get-eventlog -log EstablishedTCPConnections  | ?{$_.EventID -match "^80"}|  sort-object -property TimeGenerated -descending
$EventIDNetUnique = get-eventlog -log EstablishedTCPConnections  | ?{$_.EventID -match "^*"} | sort-object -property EventID -unique
$EventIDNetUniqueGroupBy = get-eventlog -log EstablishedTCPConnections  | ?{$_.EventID -match "^*"} | group-object -property EventID | Sort-object -property count -descending
Function Get-PortType ($CountPortType) { get-eventlog -log EstablishedTCPConnections  | ?{$_.EventID -match "^$CountPortType"} |  group-object -property EventID | Sort-object -property count -descending}

$Source = get-eventlog -log EstablishedTCPConnections | group-object -property Source | sort-object -property Count -descending
$Port = get-eventlog -log EstablishedTCPConnections | group-object -property EventID  | sort-object -property Count -descending

$UniqSource = get-eventlog -log EstablishedTCPConnections |  sort-object -property Source -descending -unique 
$UniqPort = get-eventlog -log EstablishedTCPConnections |  sort-object -property EventID -descending -unique 

$UniqSource = get-eventlog -log EstablishedTCPConnections | group-object -property Source | sort-object -property Count -descending
$UniqSource | Select Count,Name | cvhtml > UniqSource.html

$a | %{[System.Net.DNS]::Resolve($_.Source)}
$a | %{whois ($_.Source)}           

Thursday, February 12, 2009

This function pushes off the stack every new Established TCP connection as so:

PS >List-EstablishedTCP
209.62.20.43 ev1s-209-62-20-43.theplanet.com : 80
72.30.190.105 rc10.ysm.vip.ac2.yahoo.com : 80
165.160.9.37 165.160.9.37 : 80
66.235.133.3 dc2-3.112.2o7.net : 80
75.101.151.37 ec2-75-101-151-37.compute-1.amazonaws.com : 80
8.12.226.77 8.12.226.77 : 80
96.17.232.242 a96-17-232-242.deploy.akamaitechnologies.com : 80

It also send a message to the (classic) Event Log named "EstablishedTCPConnections" as shown here.  One PoSh blog was very helpful with this: http://winpowershell.blogspot.com/2006/07/writing-windows-events-using.html

function Global:EstablishedTCP 
{ ## start function

    $a = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
    $b = $a.GetActiveTcpConnections() | where{$_.State -eq "Established" }
        
    if ($b -ne $null -and $last_b -ne $null) 
    {
    $c = compare-object $b $last_b;
    }
    
    if ($c.SideIndicator -eq "<=" )
        {        
        $LocalAddress = $c.InputObject.LocalEndPoint.Address
        $RemoteAddress = $c.InputObject.RemoteEndPoint.Address           
        $LocalPort = $c.InputObject.LocalEndPoint.Port
        $RemotePort = $c.InputObject.RemoteEndPoint.Port
        
        $name = [System.Net.DNS]::Resolve("$RemoteAddress")
        $name_canon = $name.hostname
        
        write "$RemoteAddress $name_canon : $RemotePort"
        
        $EventLog = new-object System.Diagnostics.EventLog("EstablishedTCPConnections") 
        $EventLog.Source = "$name_canon" 
        $infoevent = [System.Diagnostics.EventLogEntryType]::Information 
        $EventLog.WriteEntry("$LocalAddress established connection to $RemoteAddress ($name_canon) from Local Port: $LocalPort to Remote Port: $RemotePort",$infoevent,$RemotePort,01) 
        }

start-sleep -m 100
$global:last_b = $b
  
} ## end function Established

function global:List-EstablishedTCP {do {EstablishedTCP} while (1)}

Sunday, February 8, 2009

This is a weird peice of code inspired by some syntax I found in Hristo Deshev's interesting book: "Pro Windows Powershell". Hristo talks about converting IDictionary objects to Hash Tables.  'PS' or 'get-process' uses the PID as the hash code for the process object. This allows a construct that produces a hash table with explict PIDs as hash keys. It is too late to figure out if this side-effect would have any value to anyone.

$script_block_ID = {ps | %{$_.ID} | Sort-object }
$dict = new-object Collections.Specialized.OrderedDictionary
$script_block_ID.Invoke() | %{$dict[(ps -id $_ | Select Name)] = $_.GetHashCode()}
write `r`n `$dict:
$dict 
$hash = [hashtable]$dict
write `r`n `$hash:
$hash 

[$hash:]
@{Name=cmd}                    1364                                            
@{Name=alg}                    864                                             
@{Name=explorer}               3212                                            
@{Name=gvim}                   1852                                            
@{Name=wmiprvse}               1332                                            
@{Name=VCSExpress}             3980                                            
@{Name=wscntfy}                352                                             
@{Name=chrome}                 2724                                            
@{Name=svchost}                1536 
....      

Friday, February 6, 2009

Enumerating TCP Connections

What I was looking for is a simple script to capture all new ("Established") connections.  This could use some improve since my code has some side-effects.  'Compare-object' subtracts the diff between two arrays: the reference set and the difference set. To run this I type this at a PS prompt:
  • function Est_do {do {Established} while (1)}
  • Est_do | out-file $pwd\Established.txt

function global:Established 
{
    Begin
    {
    $a = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
    }
    Process
    {
    if ($b -ne $null) {$last_b = $b}
    $b = $a.GetActiveTcpConnections()   | where{$_.State -eq "Established" }  
    if ($last_b -ne $null) 
        {$c = compare-object $last_b $b;
            if ($c.SideIndicator -eq "=>" ) {write $c.InputObject | ft -HideTableHeaders}       
        }
   $global:last_b = $b
      }
    End 
    {
    start-sleep -m 250
    }  
}


[Established.txt] :

Established 192.168.0.8:3419 209.85.147.83:80
Established 192.168.0.8:3420 74.125.19.191:80
Established 192.168.0.8:3422 74.125.19.191:80
...

Thursday, February 5, 2009

Netstat.ps1

Update 03/30/2012:
More work I did on this problem:




[back to original post...]


I spent some time seeing if Powershell could deliver some 'lsof' functionality easily with little luck. Few windows utilities do this now. Some exceptions are 'netstat -bno' (XPSP3) or tcpview.exe.  Powershell (or at least me with Powershell) can't do much with the TCPState interface despite the presence of static members:

PS > [System.Net.NetworkInformation.TcpState].GetMembers() | % {$_.Name}
...
Unknown
Closed
Listen
SynSent
SynReceived
Established
FinWait1
FinWait2
CloseWait
Closing
LastAck
TimeWait
DeleteTcb

This interface: [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
was more useful:

[netstat.ps1]
$a = [System.Net.NetworkInformation.IPGlobalProperties]::GetIPGlobalProperties()
$b = $a.GetActiveTcpListeners() | Select Address,Port | Sort Port
$c = $a.GetActiveUDPListeners() | Select Address,Port | Sort Port
$d = $a.GetActiveTcpConnections() | Select LocalEndPoint,RemoteEndPoint,State | Sort State,RemoteEndPoint
write "TCP Listeners" $b | ft -auto
write "UDP Listeners" $c | ft -auto
write "TCP Active Connections" $d | ft -auto


PS >.\netstat.ps1
TCP Listeners

Address     Port
-------     ----
0.0.0.0      135
192.168.0.5  139
192.168.0.8  139
0.0.0.0      445
127.0.0.1   1027
0.0.0.0     3389


UDP Listeners

Address     Port
-------     ----
127.0.0.1    123
192.168.0.8  123
192.168.0.5  123
192.168.0.5  137
192.168.0.8  137
192.168.0.5  138
192.168.0.8  138
0.0.0.0      445
0.0.0.0      500
192.168.0.5 1900
127.0.0.1   1900
192.168.0.8 1900
127.0.0.1   2139
127.0.0.1   2683
127.0.0.1   2704
0.0.0.0     4500


TCP Active Connections

LocalEndPoint    RemoteEndPoint          State
-------------    --------------          -----
127.0.0.1:1266   127.0.0.1:1265    Established
127.0.0.1:1265   127.0.0.1:1266    Established
127.0.0.1:1268   127.0.0.1:1267    Established
127.0.0.1:1267   127.0.0.1:1268    Established
192.168.0.8:2877 65.55.11.254:80   Established
192.168.0.8:2876 72.14.207.191:80  Established
192.168.0.8:1062 209.85.173.102:80   CloseWait