c95824a65d
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>
90 lines
3.0 KiB
PowerShell
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
|
|
}
|