Public/Start-LissWindowsFocusedCapture.ps1
|
function Start-LissWindowsFocusedCapture { <# .SYNOPSIS Creates a bounded, focused pktmon ETL and PCAPNG capture. .DESCRIPTION Requires elevation, an approved destination IP, an existing output directory, explicit approval, and explicit confirmation that pktmon is idle with no filters. The command independently checks pktmon status and filters before adding its complete filter set. It captures at most 128 bytes per packet to a 64 MB circular ETL for 5 through 120 seconds, always attempts stop in finally, converts to PCAPNG, and removes filters only when this invocation created them from a verified empty state. Captures can contain sensitive network data and are never uploaded. .PARAMETER DestinationIp Destination IPv4 or IPv6 address. Hostnames are not accepted. .PARAMETER Protocol TCP, UDP, ICMP, or ICMPv6. .PARAMETER Port Optional TCP or UDP source-or-destination port filter. .PARAMETER DurationSeconds Capture duration, from 5 through 120 seconds. .PARAMETER OutputDirectory Existing directory for ETL and PCAPNG artifacts. .PARAMETER FilePrefix Safe artifact filename prefix. .PARAMETER Approved Confirms capture authorization and artifact sensitivity. .PARAMETER ConfirmPktmonIdleAndNoFilters Explicitly confirms that the operator expects pktmon to be idle with no existing filters. The module still verifies state and refuses to proceed if activity or filters are detected. .EXAMPLE Start-LissWindowsFocusedCapture -DestinationIp 203.0.113.10 -Protocol TCP -Port 443 -DurationSeconds 15 -OutputDirectory C:\Diagnostics -Approved -ConfirmPktmonIdleAndNoFilters -Confirm:$false #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')] [OutputType('LISSTech.WindowsNetworkDiagnostics.CaptureResult')] param( [Parameter(Mandatory)][ipaddress]$DestinationIp, [Parameter(Mandatory)][ValidateSet('TCP', 'UDP', 'ICMP', 'ICMPv6')][string]$Protocol, [ValidateRange(1, 65535)][int]$Port, [ValidateRange(5, 120)][int]$DurationSeconds = 15, [Parameter(Mandatory)][ValidateScript({ Test-Path -LiteralPath $_ -PathType Container })][string]$OutputDirectory, [ValidatePattern('^[a-zA-Z0-9._-]+$')][string]$FilePrefix = 'LissNetworkCapture', [Parameter(Mandatory)][switch]$Approved, [Parameter(Mandatory)][switch]$ConfirmPktmonIdleAndNoFilters ) if (-not $Approved) { throw 'Explicit -Approved confirmation is required for packet capture.' } if (-not $ConfirmPktmonIdleAndNoFilters) { throw 'Explicit -ConfirmPktmonIdleAndNoFilters confirmation is required.' } if ($Port -and $Protocol -notin @('TCP', 'UDP')) { throw '-Port is supported only with TCP or UDP.' } if (-not (Test-LissAdministrator)) { throw 'An elevated Windows administrator session is required for pktmon capture.' } if (-not (Get-Command pktmon.exe -CommandType Application -ErrorAction SilentlyContinue)) { throw 'pktmon.exe is unavailable on this Windows version.' } $capability = Get-LissPktmonCapability if (-not $capability.Supported) { throw "This pktmon version lacks required capture capabilities: $($capability.MissingCapabilities -join ', ')." } $state = Get-LissPktmonState if ($state.IsCaptureActive) { throw 'pktmon is already capturing. Refusing to disrupt the existing capture.' } if ($state.HasFilters) { throw 'pktmon already has filters. Refusing to call filter remove or alter the existing filter set.' } $destination = $DestinationIp.IPAddressToString $target = "$Protocol traffic involving $destination for $DurationSeconds seconds in '$OutputDirectory'" if (-not $PSCmdlet.ShouldProcess($target, 'Create sensitive ETL and PCAPNG capture artifacts')) { return } $stamp = Get-Date -Format 'yyyyMMdd-HHmmss' $etlPath = Join-Path $OutputDirectory "$FilePrefix-$stamp.etl" $pcapngPath = Join-Path $OutputDirectory "$FilePrefix-$stamp.pcapng" $filterCreated = $false $startAttempted = $false $stopError = $null $cleanupError = $null $started = Get-Date try { $filterArguments = @('filter', 'add', 'LISSTechFocusedCapture', '-i', $destination, '-t', $Protocol) if ($Port) { $filterArguments += @('-p', [string]$Port) } $filterResult = Invoke-LissPktmonCommand -ArgumentList $filterArguments if ($filterResult.ExitCode -ne 0) { throw "pktmon filter add failed: $($filterResult.Output -join ' ')" } $filterCreated = $true $startAttempted = $true $startResult = Invoke-LissPktmonCommand -ArgumentList @('start', '--capture', '--pkt-size', '128', '--file-name', $etlPath, '--file-size', '64', '--log-mode', 'circular') if ($startResult.ExitCode -ne 0) { throw "pktmon start failed: $($startResult.Output -join ' ')" } Start-Sleep -Seconds $DurationSeconds } finally { if ($startAttempted) { $stopResult = Invoke-LissPktmonCommand -ArgumentList @('stop') if ($stopResult.ExitCode -ne 0) { $stopError = $stopResult.Output -join ' ' Write-Warning "pktmon stop failed: $stopError" } } if ($filterCreated) { $removeResult = Invoke-LissPktmonCommand -ArgumentList @('filter', 'remove') if ($removeResult.ExitCode -ne 0) { $cleanupError = $removeResult.Output -join ' ' Write-Warning "pktmon filter cleanup failed: $cleanupError" } } } if ($stopError) { throw "Capture stop failed; ETL state may be incomplete: $stopError" } if (-not (Test-Path -LiteralPath $etlPath -PathType Leaf)) { throw "pktmon did not create the expected ETL artifact '$etlPath'." } $convertResult = Invoke-LissPktmonCommand -ArgumentList @('etl2pcap', $etlPath, '--out', $pcapngPath) if ($convertResult.ExitCode -ne 0 -or -not (Test-Path -LiteralPath $pcapngPath -PathType Leaf)) { throw "pktmon ETL to PCAPNG conversion failed: $($convertResult.Output -join ' ')" } [pscustomobject]@{ PSTypeName = 'LISSTech.WindowsNetworkDiagnostics.CaptureResult' DestinationIp = $destination Protocol = $Protocol Port = if ($Port) { $Port } else { $null } DurationSeconds = $DurationSeconds StartedAt = $started CompletedAt = Get-Date PacketBytes = 128 CircularSizeMB = 64 EtlPath = $etlPath PcapngPath = $pcapngPath FilterRemoved = -not [bool]$cleanupError CleanupError = $cleanupError ArtifactWarning = 'ETL and PCAPNG files can contain sensitive endpoint network data. Store and share them only through approved channels.' } } |