03 / INCIDENT TRIAGE WORKFLOWS · LESSON 09

Reconstruct process relationships

Join process records by host and process identity while making missing parent evidence visible.

12 min · learn at your pace

A process ID is not a permanent identity

Operating systems reuse numeric process IDs. Joining all historical records by ProcessId can attach an observation to the wrong process. This normalised dataset uses ProcessGuid and ParentProcessGuid to distinguish process instances, plus Computer to keep hosts separate.

The shape resembles selected Sysmon fields; it is not raw Sysmon XML. Real collection depends on Windows, installed tooling, configuration, permissions, and retention. Everything needed here is already supplied in JSON.

Join without dropping gaps

For each process, find a row on the same computer whose ProcessGuid equals that process's ParentProcessGuid. If no parent row exists, emit Unknown as the parent image. The parent might predate the export or be missing from collection. Do not silently delete the child record or invent a parent.

Get-Content '/home/user/processes.json' -Raw |
    ConvertFrom-Json -DateKind String |
    Select-Object Computer, ProcessGuid, Image

-DateKind String keeps JSON timestamps as their original strings in this PowerShell 7.6 lab. Parse them explicitly when a task needs time arithmetic.

A process name and its parent are useful context, not a determination of maliciousness. Legitimate administration also launches shells. Later analysis should combine command details, user activity, signatures, timing, and other observations when available.

Go deeper

Read the official reference.

Try an example.ps1
Get-Content '/home/user/processes.json' -Raw | ConvertFrom-Json -DateKind String | Select-Object RecordId, Computer, Image
YOUR TURN

Put it into practice.

For every processes.json record, emit RecordId, Computer, Image, and ParentImage. Join a parent using both Computer and ParentProcessGuid = ProcessGuid. Use ParentImage Unknown when no parent record is present. Preserve all five records; do not join on numeric ProcessId.

See an explained solution
One way to solve it.ps1
$events = @(Get-Content '/home/user/processes.json' -Raw | ConvertFrom-Json -DateKind String)
foreach ($event in $events) {
    $parent = $events | Where-Object { $_.Computer -eq $event.Computer -and $_.ProcessGuid -eq $event.ParentProcessGuid }
    [pscustomobject]@{ RecordId=$event.RecordId; Computer=$event.Computer; Image=$event.Image; ParentImage=$(if ($parent) { $parent.Image } else { 'Unknown' }) }
}

The host-plus-GUID join attaches each child to the right parent. Unknown means the export has a gap, so it remains explicit rather than disappearing from the report.