Payload/scripts/kaden/utils/sensor-fail-extract.ps1
|
<# .SYNOPSIS Extract failure-focused lines from a harness sensor JSON file. .DESCRIPTION Loads a sensor artifact JSON, prints key metadata, then scans selected text fields for lines that match a regex pattern. This replaces one-off scripts that hardcode a specific sensor path. .PARAMETER SensorPath Path to a sensor JSON file. Relative paths resolve from current directory, then from the repository root. .PARAMETER Pattern Regex used to extract interesting lines from text fields. Default: lines that start with "[-]". .PARAMETER Fields Sensor fields to scan for Pattern. .EXAMPLE pwsh -NoProfile -File .\scripts\kaden\utils\sensor-fail-extract.ps1 -SensorPath docs\harness\features\harness-event-journal\sensors\harness-run-slice-tests-20260928T221703Z.json .EXAMPLE pwsh -NoProfile -File .\scripts\kaden\utils\sensor-fail-extract.ps1 -SensorPath .\my-sensor.json -Pattern "(?i)exception|error|fail" .EXAMPLE Get-Help .\scripts\kaden\utils\sensor-fail-extract.ps1 -Parameter Pattern #> #Requires -Version 5.1 [CmdletBinding(DefaultParameterSetName = "Run")] param( [Parameter(ParameterSetName = "Run", Mandatory = $true, Position = 0)] [string]$SensorPath, [Parameter(ParameterSetName = "Run")] [string]$Pattern = "(?m)^\[-\].+$", [Parameter(ParameterSetName = "Run")] [string[]]$Fields = @( "stdout_tail", "stderr_tail", "stdout", "stderr", "output_tail", "command_stdout_tail", "inner_stdout_tail", "failure_summary", "evidence_summary" ), [Parameter(ParameterSetName = "Help")] [Alias("h", "help")] [switch]$ShowHelp ) Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" function Resolve-SensorExtractRepoRoot { $current = $PSScriptRoot while ($true) { $marker = Join-Path $current "package.json" if (Test-Path -LiteralPath $marker) { return $current } $parent = Split-Path $current -Parent if ([string]::IsNullOrWhiteSpace($parent) -or $parent -eq $current) { throw "Could not locate repository root (package.json) from this script." } $current = $parent } } function Resolve-SensorExtractPath { param( [Parameter(Mandatory = $true)][string]$InputPath, [Parameter(Mandatory = $true)][string]$RepoRoot ) if (Test-Path -LiteralPath $InputPath) { return (Resolve-Path -LiteralPath $InputPath).Path } if (-not [System.IO.Path]::IsPathRooted($InputPath)) { $candidate = Join-Path $RepoRoot $InputPath if (Test-Path -LiteralPath $candidate) { return (Resolve-Path -LiteralPath $candidate).Path } } throw "Sensor file not found: $InputPath. Get-Help `"$PSCommandPath`" -Parameter SensorPath" } $repoRoot = Resolve-SensorExtractRepoRoot $cliKitManifest = Join-Path $PSScriptRoot "PsCliUiKit\PsCliUiKit.psd1" if (-not (Test-Path -LiteralPath $cliKitManifest)) { throw "PsCliUiKit manifest not found: $cliKitManifest" } Import-Module -Name $cliKitManifest -Force try { if ($ShowHelp) { (Get-Help -Name $PSCommandPath -Full | Out-String -Width 100) | Out-Host return } $fullPath = Resolve-SensorExtractPath -InputPath $SensorPath -RepoRoot $repoRoot if ($Pattern.Length -gt 400) { throw "Pattern is too long. Get-Help `"$PSCommandPath`" -Parameter Pattern" } try { $null = [regex]::new($Pattern) } catch { throw "Invalid pattern: $($_.Exception.Message) Get-Help `"$PSCommandPath`" -Parameter Pattern" } $sensor = Get-Content -LiteralPath $fullPath -Raw -Encoding UTF8 | ConvertFrom-Json Write-CliSection -Title "Sensor" -Style "info" Write-CliKeyValue -Label "path" -Value $fullPath -LabelWidth 14 if ($sensor.PSObject.Properties.Name -contains "name") { Write-CliKeyValue -Label "sensor" -Value ([string]$sensor.name) -LabelWidth 14 } if ($sensor.PSObject.Properties.Name -contains "command") { Write-CliKeyValue -Label "command" -Value ([string]$sensor.command) -LabelWidth 14 } if ($sensor.PSObject.Properties.Name -contains "inner_command") { Write-CliKeyValue -Label "inner command" -Value ([string]$sensor.inner_command) -LabelWidth 14 } if ($sensor.PSObject.Properties.Name -contains "exit_code") { Write-CliKeyValue -Label "sensor exit" -Value ([string]$sensor.exit_code) -LabelWidth 14 } if ($sensor.PSObject.Properties.Name -contains "summary") { Write-CliKeyValue -Label "failure" -Value ([string]$sensor.summary) -LabelWidth 14 } $totalMatches = 0 $printedExtracted = $false foreach ($field in $Fields) { if ($sensor.PSObject.Properties.Name -notcontains $field) { continue } $value = [string]$sensor.$field if ([string]::IsNullOrWhiteSpace($value)) { continue } $fieldMatches = [regex]::Matches($value, $Pattern) if ($fieldMatches.Count -eq 0) { continue } $totalMatches += $fieldMatches.Count if (-not $printedExtracted) { Write-CliColor -Message "" Write-CliColor -Message " [muted]extracted[-]" $printedExtracted = $true } Write-CliColor -Message " [muted]$field[-]" foreach ($match in $fieldMatches) { $lines = @( $match.Value -split "\r?\n" | ForEach-Object { $_.TrimEnd() } | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } ) Write-CliList -Item $lines -Bullet "!" -Indent 4 -Literal } } if ($totalMatches -eq 0) { Write-CliStatus -State "Info" -Message "No lines matched pattern: $Pattern" } else { Write-CliStatus -State "Success" -Message "$totalMatches matching line(s) extracted." } } catch { Write-CliSection -Title "Sensor extract failed" -Style "error" Write-CliStatus -State "Error" -Message $_.Exception.Message exit 2 } finally { Write-CliEnd } |