Files
histsdk/scripts/Run-PktmonDebianRelayCapture.ps1
dohertj2 c95824a65d Initial commit: managed .NET 10 AVEVA Historian SDK + reverse-engineering toolkit
Full read-only SDK (src/AVEVA.Historian.Client) implementing the CLAUDE.md required
surface against AVEVA Historian's binary WCF protocol — no native AVEVA runtime
dependency. All operations live-verified against a local Historian:

- ProbeAsync, ReadRawAsync, ReadAggregateAsync, ReadAtTimeAsync, ReadEventsAsync
- BrowseTagNamesAsync, GetTagMetadataAsync (17 native data-type codes mapped)
- GetConnectionStatusAsync, GetStoreForwardStatusAsync, GetSystemParameterAsync
- 108/108 unit + integration tests pass

Includes the reverse-engineering toolkit (tools/AVEVA.Historian.ReverseEngineering)
used to decode the protocol: WCF probes, IL inspection via dnlib, and IL-rewrite
instrumentation (instrument-wcf-{write,read}message etc.) plus the .NET Framework
trace harness (tools/AVEVA.Historian.NativeTraceHarness) for parity testing.

Sanitized handoff evidence under docs/reverse-engineering/. Native AVEVA binaries
(current/, aveva-install-x64/, aveva-install-x86/) are gitignored — fetch separately
from the AVEVA installer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 06:31:48 -04:00

90 lines
3.0 KiB
PowerShell

param(
[string]$SshUser = "dohertj2",
[string]$SshHost = "10.100.0.35",
[string]$TargetHost = "10.100.0.48",
[ValidateSet("history", "event")]
[string]$Scenario = "history",
[string]$TagName = "OtOpcUaParityTest_001.Counter",
[int]$LookbackMinutes = 1440,
[int]$MaxRows = 1,
[string]$OutputPrefix = $null
)
$ErrorActionPreference = "Stop"
$PSNativeCommandUseErrorActionPreference = $false
$repoRoot = Split-Path -Parent $PSScriptRoot
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
if ([string]::IsNullOrWhiteSpace($OutputPrefix)) {
$OutputPrefix = Join-Path $repoRoot "docs\reverse-engineering\pktmon-debian-relay-$Scenario-latest"
}
$outputDirectory = Split-Path -Parent $OutputPrefix
New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null
$etlPath = "$OutputPrefix.etl"
$txtPath = "$OutputPrefix.txt"
$statsPath = "$OutputPrefix.stats.txt"
$relayPath = "$OutputPrefix.relay.ndjson"
$harnessPath = "$OutputPrefix.harness.json"
Push-Location $repoRoot
try {
cmd.exe /c "pktmon stop >nul 2>nul" | Out-Null
cmd.exe /c "pktmon filter remove >nul 2>nul" | Out-Null
pktmon filter add HistRelay -i $SshHost -p 32568 -t TCP | Out-Null
# 0x00e intentionally omits 0x010 raw-packet bytes. Keep metadata only.
pktmon start --capture --comp nics --flags 0x00e --file-name $etlPath --log-mode circular --file-size 64 | Out-Host
try {
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\scripts\Run-DebianHistorianRelayCapture.ps1 `
-SshUser $SshUser `
-SshHost $SshHost `
-TargetHost $TargetHost `
-Scenario $Scenario `
-TagName $TagName `
-LookbackMinutes $LookbackMinutes `
-MaxRows $MaxRows `
-OutputPath $relayPath `
-HarnessOutputPath $harnessPath
$harnessExit = $LASTEXITCODE
}
finally {
pktmon stop | Out-Host
}
pktmon etl2txt $etlPath --out $txtPath --brief | Out-Host
pktmon etl2txt $etlPath --stats-only 2>&1 | Set-Content -Path $statsPath -Encoding UTF8
Get-Content -Path $statsPath | Out-Host
Remove-Item -LiteralPath $etlPath -Force -ErrorAction SilentlyContinue
cmd.exe /c "pktmon filter remove >nul 2>nul" | Out-Null
$summary = [pscustomobject]@{
Operation = "PktmonDebianRelayCapture"
Scenario = $Scenario
SshHost = $SshHost
TargetHost = $TargetHost
HarnessExitCode = $harnessExit
PayloadBytesCaptured = $false
PktmonText = $txtPath
PktmonStats = $statsPath
RelayTranscript = $relayPath
HarnessOutput = $harnessPath
RawEtlDeleted = -not (Test-Path -LiteralPath $etlPath)
}
$summary | ConvertTo-Json -Depth 4 | Set-Content -Path "$OutputPrefix.summary.json" -Encoding UTF8
exit $harnessExit
}
finally {
try {
cmd.exe /c "pktmon stop >nul 2>nul" | Out-Null
cmd.exe /c "pktmon filter remove >nul 2>nul" | Out-Null
}
catch {
}
Pop-Location
}