Public/Export-TripwireReport.ps1
|
<# .SYNOPSIS Write scored trips to a self-contained HTML report, JSON, or a SIEM-ready JSONL stream. .DESCRIPTION Html and Json are free. Jsonl and -WebhookUri are the SOAR path and require the 'soar' Pro feature. Whatever the format, the coverage line comes with the findings: how many trips were scored with a signal withheld, and how many were suppressed. A quiet report from a blind run must not read like a quiet tenant. .PARAMETER Trip Scored trips. .PARAMETER Path Output file. Defaults to a timestamped name in the working directory. .PARAMETER Format Html (default), Json, or Jsonl. .PARAMETER WebhookUri POST each trip as JSON to a SOAR or SIEM ingest endpoint. Pro ('soar'). .PARAMETER TenantLabel Free text for the report header. .EXAMPLE Watch-TripwireActivity -Demo | Export-TripwireReport -Path ./demo-report.html #> function Export-TripwireReport { [CmdletBinding(SupportsShouldProcess)] [OutputType([string])] param( [Parameter(Mandatory, ValueFromPipeline)] $Trip, [string] $Path, [ValidateSet('Html', 'Json', 'Jsonl')] [string] $Format = 'Html', [string] $WebhookUri, [string] $TenantLabel = 'unspecified tenant', [switch] $Demo ) begin { $collected = [System.Collections.Generic.List[object]]::new() } process { $collected.Add($Trip) } end { if (($Format -eq 'Jsonl' -or $WebhookUri) -and -not (Test-TripwireFeature -Feature 'soar')) { throw "JSONL and webhook delivery are an EntraTripwire Pro feature (soar). Html and Json exports are free and contain the same data. See docs/PRO.md." } if (-not $Path) { $ext = $Format.ToLowerInvariant() $Path = Join-Path (Get-Location) ("tripwire-report-{0:yyyyMMdd-HHmmss}.{1}" -f [DateTime]::UtcNow, $ext) } $trips = @($collected) $content = switch ($Format) { 'Html' { ConvertTo-TripwireHtmlReport -Trip $trips -TenantLabel $TenantLabel -Demo:$Demo } 'Json' { $trips | ConvertTo-Json -Depth 10 } 'Jsonl' { ($trips | ForEach-Object { $_ | ConvertTo-Json -Depth 10 -Compress }) -join "`n" } } if ($PSCmdlet.ShouldProcess($Path, "Write $Format report for $($trips.Count) trip(s)")) { Set-Content -LiteralPath $Path -Value $content -Encoding utf8 $degraded = @($trips | Where-Object { $_.Degraded }).Count $suppressed = @($trips | Where-Object { $_.Band -eq 'Suppressed' }).Count Write-TripwireLog -Message "Wrote $Path -- $($trips.Count) trips, $degraded scored degraded, $suppressed suppressed." } if ($WebhookUri) { foreach ($t in $trips) { if (-not $PSCmdlet.ShouldProcess($WebhookUri, "POST trip $($t.TouchId)")) { continue } Send-TripwireWebhook -Uri $WebhookUri -Trip $t } } return $Path } } |