src/Private/Core/Get-FotonCollectionWindow.ps1
|
function Get-FotonCollectionWindow { <# .SYNOPSIS Returns the UTC start and end of the collection recorded in a package. .DESCRIPTION Analysis needs to know when the collector was running so that events caused by Foton itself can be separated from events about the host. Script block logging records the collector's own PowerShell, so hunt engines report the collection as suspicious scripting activity. The window comes from 00_Collection\collection.log, which stamps every line "yyyy-MM-dd HH:mm:ss UTC"; the earliest and latest stamps bound the run. chain_of_custody.txt supplies the start if the log is unreadable, but it records no end, so no window is returned in that case - a start without an end cannot bound anything, and guessing a duration would invent evidence. Returns $null when the window cannot be established. Callers must treat that as "cannot attribute", not as "nothing to attribute". .EXAMPLE $w = Get-FotonCollectionWindow -CaseRoot $script:FotonSession.CaseRoot if ($w) { "Collector ran {0} to {1}" -f $w.StartUtc, $w.EndUtc } Bounds the collection so time-based attribution can run. #> param([string]$CaseRoot) if (-not $CaseRoot -or -not (Test-Path -LiteralPath $CaseRoot)) { return $null } $log = Join-Path $CaseRoot '00_Collection\collection.log' if (-not (Test-Path -LiteralPath $log)) { return $null } $min = $null $max = $null try { foreach ($line in (Get-Content -LiteralPath $log -ErrorAction Stop)) { $m = [regex]::Match($line, '^(?<ts>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) UTC') if (-not $m.Success) { continue } $d = [datetime]::MinValue if (-not [datetime]::TryParseExact($m.Groups['ts'].Value, 'yyyy-MM-dd HH:mm:ss', [Globalization.CultureInfo]::InvariantCulture, [Globalization.DateTimeStyles]::AssumeUniversal -bor [Globalization.DateTimeStyles]::AdjustToUniversal, [ref]$d)) { continue } if ($null -eq $min -or $d -lt $min) { $min = $d } if ($null -eq $max -or $d -gt $max) { $max = $d } } } catch { } if ($null -eq $min -or $null -eq $max) { return $null } return [PSCustomObject]@{ StartUtc = [datetimeoffset]::new($min, [timespan]::Zero) EndUtc = [datetimeoffset]::new($max, [timespan]::Zero) } } |