158 lines
6.6 KiB
PowerShell
158 lines
6.6 KiB
PowerShell
param(
|
|
[string] $RavenHost = "raven",
|
|
[string] $MuninnExe = "C:\Meta\Odin\Muninn\muninn.exe",
|
|
[string] $StorePath = "C:\Meta\Odin\state\muninn.telemetry.cc",
|
|
[string] $ActivateStorePath = "C:\Meta\Odin\state\muninn.activate.cc",
|
|
[string] $LogRoot = "C:\Meta\Odin\logs\muninn",
|
|
[int] $MaxStoreAgeSeconds = 180,
|
|
[string] $IdunnRudpHealth = "10.77.0.2:17870"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Set-AsciiFile {
|
|
param(
|
|
[Parameter(Mandatory = $true)] [string] $Path,
|
|
[Parameter(Mandatory = $true)] [string] $Content
|
|
)
|
|
|
|
[System.IO.File]::WriteAllText($Path, ($Content -replace "`r?`n", "`r`n"), [System.Text.Encoding]::ASCII)
|
|
}
|
|
|
|
function Invoke-RavenUploadedPowerShell {
|
|
param(
|
|
[Parameter(Mandatory = $true)] [string] $RavenHost,
|
|
[Parameter(Mandatory = $true)] [string] $RemoteScriptContent,
|
|
[Parameter(Mandatory = $true)] [string] $TempPrefix
|
|
)
|
|
|
|
$uploadId = [guid]::NewGuid().ToString("N")
|
|
$localTempRoot = Join-Path $env:TEMP "$TempPrefix-$uploadId"
|
|
$localRemoteScript = Join-Path $localTempRoot "$TempPrefix-$uploadId.ps1"
|
|
$localSftpBatch = Join-Path $localTempRoot "$TempPrefix-$uploadId.sftp"
|
|
$remoteSftpPath = "C:/Windows/Temp/$TempPrefix-$uploadId.ps1"
|
|
$remotePsPath = "C:\Windows\Temp\$TempPrefix-$uploadId.ps1"
|
|
|
|
try {
|
|
New-Item -ItemType Directory -Force -Path $localTempRoot | Out-Null
|
|
Set-AsciiFile -Path $localRemoteScript -Content $RemoteScriptContent
|
|
Set-AsciiFile -Path $localSftpBatch -Content ('put "{0}" "{1}"' -f $localRemoteScript, $remoteSftpPath)
|
|
|
|
& sftp.exe -b $localSftpBatch $RavenHost
|
|
if ($LASTEXITCODE -ne 0) {
|
|
exit $LASTEXITCODE
|
|
}
|
|
|
|
$remoteRunner = @"
|
|
`$ErrorActionPreference = "Stop"
|
|
try {
|
|
& "$remotePsPath"
|
|
`$code = `$LASTEXITCODE
|
|
} finally {
|
|
Remove-Item -LiteralPath "$remotePsPath" -Force -ErrorAction SilentlyContinue
|
|
}
|
|
exit `$code
|
|
"@
|
|
$encodedRunner = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($remoteRunner))
|
|
& ssh.exe -o BatchMode=yes -o ConnectTimeout=10 $RavenHost "powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -EncodedCommand $encodedRunner"
|
|
} finally {
|
|
Remove-Item -LiteralPath $localTempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|
|
}
|
|
|
|
$remoteScript = @"
|
|
`$ErrorActionPreference = "Stop"
|
|
`$ProgressPreference = "SilentlyContinue"
|
|
if (-not (Test-Path -LiteralPath "$MuninnExe")) {
|
|
throw "Muninn executable not found at $MuninnExe"
|
|
}
|
|
`$muninnDir = Split-Path -Parent "$MuninnExe"
|
|
`$taskExpectations = @(
|
|
@{ Name = "GameCult-Muninn"; Vbs = Join-Path `$muninnDir "start-muninn-serve-hidden.vbs"; Ps = Join-Path `$muninnDir "start-muninn-serve.ps1" },
|
|
@{ Name = "GameCult-Muninn-Activate"; Vbs = Join-Path `$muninnDir "activate-raven-av-srt-hidden.vbs"; Ps = Join-Path `$muninnDir "activate-raven-av-srt.ps1" },
|
|
@{ Name = "GameCult-Muninn-VideoProof"; Vbs = Join-Path `$muninnDir "muninn-raven-video-to-starfire-obs-hidden.vbs"; Ps = Join-Path `$muninnDir "muninn-raven-video-to-starfire-obs.ps1" }
|
|
)
|
|
foreach (`$expectation in `$taskExpectations) {
|
|
`$task = Get-ScheduledTask -TaskName `$expectation.Name -ErrorAction Stop
|
|
`$action = @(`$task.Actions)[0]
|
|
if (`$action.Execute -notmatch '(^|\\)wscript\.exe$') {
|
|
throw "`$(`$expectation.Name) action executes `$(`$action.Execute), expected wscript.exe"
|
|
}
|
|
if (`$action.Arguments -notlike "*`$(`$expectation.Vbs)*") {
|
|
throw "`$(`$expectation.Name) action arguments `$(`$action.Arguments) do not reference `$(`$expectation.Vbs)"
|
|
}
|
|
if (`$action.Arguments -notlike "*//B*" -or `$action.Arguments -notlike "*//Nologo*") {
|
|
throw "`$(`$expectation.Name) action arguments `$(`$action.Arguments) do not force hidden WScript execution"
|
|
}
|
|
if (-not (Test-Path -LiteralPath `$expectation.Vbs)) {
|
|
throw "Missing hidden launcher for `$(`$expectation.Name) at `$(`$expectation.Vbs)"
|
|
}
|
|
if (-not (Test-Path -LiteralPath `$expectation.Ps)) {
|
|
throw "Missing PowerShell launcher for `$(`$expectation.Name) at `$(`$expectation.Ps)"
|
|
}
|
|
`$psContent = Get-Content -LiteralPath `$expectation.Ps -Raw
|
|
if (`$psContent -like "*'' | ConvertFrom-Json*") {
|
|
throw "`$(`$expectation.Ps) has an empty encoded-arguments payload"
|
|
}
|
|
if (`$psContent -notmatch 'Start-Process') {
|
|
throw "`$(`$expectation.Ps) does not launch a hidden process"
|
|
}
|
|
if (`$expectation.Name -eq "GameCult-Muninn-VideoProof" -and `$psContent -notmatch 'ffmpeg\.exe') {
|
|
throw "`$(`$expectation.Ps) does not launch ffmpeg.exe"
|
|
}
|
|
if (`$expectation.Name -eq "GameCult-Muninn-VideoProof" -and `$psContent -notmatch 'srt://.+:\d+\?mode=caller') {
|
|
throw "`$(`$expectation.Ps) does not carry the expected SRT caller target"
|
|
}
|
|
`$vbs = Get-Content -LiteralPath `$expectation.Vbs -Raw
|
|
if (`$vbs -match 'cmdPath\s*=') {
|
|
throw "`$(`$expectation.Vbs) still routes through a cmdPath trampoline"
|
|
}
|
|
if (`$vbs -notmatch '\.ps1') {
|
|
throw "`$(`$expectation.Vbs) does not reference a PowerShell launcher"
|
|
}
|
|
}
|
|
`$process = Get-CimInstance Win32_Process |
|
|
Where-Object { `$_.Name -ieq "muninn.exe" -and `$_.CommandLine -like "*serve*" } |
|
|
Select-Object -First 1
|
|
if (`$null -eq `$process) {
|
|
throw "Muninn serve process is not running"
|
|
}
|
|
foreach (`$pattern in @(
|
|
"--host raven",
|
|
"--activate-store $ActivateStorePath",
|
|
"--capture-command-rudp-bind 0.0.0.0:17872",
|
|
"--idunn-rudp-health $IdunnRudpHealth",
|
|
"--idunn-daemon muninn",
|
|
"--idunn-health-contract muninn.cultnet-rudp-remote-telemetry-health"
|
|
)) {
|
|
if (`$process.CommandLine -notlike "*`$pattern*") {
|
|
throw "Muninn serve process is missing expected command-line segment `${pattern}: `$(`$process.CommandLine)"
|
|
}
|
|
}
|
|
`$conflictingWriter = Get-CimInstance Win32_Process |
|
|
Where-Object {
|
|
`$_.Name -like "muninn*.exe" -and
|
|
`$_.ProcessId -ne `$process.ProcessId -and
|
|
`$_.ParentProcessId -ne `$process.ProcessId -and
|
|
`$_.CommandLine -like "*activate*" -and
|
|
`$_.CommandLine -like "*$StorePath*"
|
|
} |
|
|
Select-Object -First 1
|
|
if (`$null -ne `$conflictingWriter) {
|
|
throw "Conflicting Muninn activate writer still targets ${StorePath}: `$(`$conflictingWriter.CommandLine)"
|
|
}
|
|
if (-not (Test-Path -LiteralPath "$StorePath")) {
|
|
throw "Muninn telemetry store is missing at $StorePath"
|
|
}
|
|
`$storeAgeSeconds = (([DateTime]::UtcNow) - (Get-Item -LiteralPath "$StorePath").LastWriteTimeUtc).TotalSeconds
|
|
if (`$storeAgeSeconds -gt $MaxStoreAgeSeconds) {
|
|
throw "Muninn telemetry store is stale (`$([math]::Round(`$storeAgeSeconds))s old)"
|
|
}
|
|
`$servePidPath = Join-Path "$LogRoot" "muninn-serve.pid"
|
|
if (-not (Test-Path -LiteralPath `$servePidPath)) {
|
|
throw "Muninn serve PID file is missing at `$servePidPath"
|
|
}
|
|
"@
|
|
|
|
Invoke-RavenUploadedPowerShell -RavenHost $RavenHost -RemoteScriptContent $remoteScript -TempPrefix "odin-raven-muninn-health"
|
|
exit $LASTEXITCODE
|