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>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user