# encoding: ascii
# api: powershell
# title: SharpPcap
# description: Your first steps at capturing packets from PowerShell with WinPcap via SharpPcap
# version: 4.7
# type: script
# author: Joel Bennett
# license: CC0
# x-poshcode-id: 5374
# x-archived: 2014-08-24T13:26:44
# x-published: 2014-08-19T23:11:00
#
#
# First, you have to install WinPcap
# http://www.winpcap.org/install/default.htm
# Then, you have to download SharpPcap
# http://sourceforge.net/projects/sharppcap/
# And you need to import the assembly from wherever you put it
Add-Type -Path $SkyProfileDir\Libraries\SharpPcap*\SharpPcap.dll
# To avoid crashing, you MUST avoid accessing the NonBlockingMode property
# But I also want to expose the Interface.FriendlyName because it's the meaningful name
Update-TypeData -TypeName SharpPcap.WinPcap.WinPcapDevice `
-MemberName FriendlyName -MemberType ScriptProperty -Value { $this.Interface.FriendlyName }
Update-TypeData -TypeName SharpPcap.WinPcap.WinPcapDevice `
-DefaultDisplayProperty FriendlyName -DefaultDisplayPropertySet FriendlyName, Addresses, Description, MacAddress
# The MacAddress property doesn't seem to work right now, but Interface.MacAddress does
Update-TypeData -TypeName SharpPcap.WinPcap.WinPcapDevice `
-MemberName MacAddress -MemberType ScriptProperty -Value { $this.Interface.MacAddress } -Force
# By default, PcapAddress ToString() shows the address and netmask etc. which we don't need to see all the time.
Update-TypeData -TypeName SharpPcap.LibPcap.PcapAddress `
-DefaultDisplayProperty Addr -MemberName ToString -MemberType ScriptMethod -Value { $this.Addr.ToString() } -Force
# Then you need to pick a device to capture with
[SharpPcap.CaptureDeviceList]::Instance | Format-Table FriendlyName, Addresses, Description, MacAddress -Auto -Wrap
# If the pipeline-enabled Read-Choice is available:
Import-Module Reflection -Min 4.7 -ErrorAction SilentlyContinue
if($choose = get-command Read-Choice* | ? { $_.Parameters.Values.GetEnumerator() | % Attributes | % ValueFromPipeline }) {
$device = [SharpPcap.CaptureDeviceList]::Instance |
&$choose -Prompt "Please choose a device for capture:" -Label FriendlyName -Passthru
} else {
$device = [SharpPcap.CaptureDeviceList]::Instance |
Where { $_.Addresses.Addr -like "192.*" } |
Select -First 1
}
Get-EventSubscriber -Source $device.MacAddress -EA 0 | Where EventName -eq OnPacketArrival | Unregister-Event
$null = Register-ObjectEvent $device -EventName OnPacketArrival -Source $device.MacAddress {
try {
# Do something useful with the CaptureEventArgs in $EventArgs:
$Packet = [PacketDotNet.Packet]::ParsePacket($EventArgs.Packet.LinkLayerType, $EventArgs.Packet.Data)
# If you just want the TcpPacket:
# $Packet = $Packet.Extract([PacketDotNet.TcpPacket])
# If you want to see what you could be doing ...
# $Packet | Get-Member | Out-String -Stream | % Trim | Write-Host
# This isn't useful, but it's a nice demo
Write-Host ([DateTime]$EventArgs.Packet.Timeval.Date) "Len=" $EventArgs.Packet.Data.Length -Foreground Cyan
Write-Host $Packet.ToString()
} catch {
Write-Host "ERROR:" $_ -Foreground Red
}
}
Write-Host "Capturing on" $device.FriendlyName
$device.Open([SharpPcap.DeviceMode]::Promiscuous, 1000);
# Receive only TCP packets
$device.Filter = "tcp"
$device.StartCapture()
# Listen for a while ...
# In order to make sure the "host" output of the event handler shows up ...
# We should Write-Host on the current thread (ugh, that's screwy)
for($msec=0; $msec -lt 3000; $msec += 100) {
Start-Sleep -milli 100
Write-Host -NoNewLine
}
# Clean up
$device.StopCapture()
$device.Close()