$p = Get-CimInstance -ClassName "win32_process" | Select-Object ProcessId, ParentProcessId, CommandLine
$d = @{}; $c = @{}
foreach ($proc in $p) { $d[$proc.ProcessId] = $proc; $c[$proc.ProcessId] = @() }
foreach ($proc in $p) { if ($proc.ParentProcessId -ne 0 -and $c.ContainsKey($proc.ParentProcessId)) { $c[$proc.ParentProcessId] += $proc } }
function Get-ProcessAndChildProcesses {
param([int]$Level, [psobject]$proc)
$cmdLine = if ($proc.CommandLine) { $proc.CommandLine } else { $proc.Name }
"{0}[{1,5}] - {2}" -f (" " * $Level), $proc.ProcessId, $cmdLine
if ($c.ContainsKey($proc.ProcessId)) { $c[$proc.ProcessId] | ForEach-Object { Get-ProcessAndChildProcesses ($Level + 1) $_ } }
}
$r = $p | Where-Object { $_.ParentProcessId -eq 0 -or -not $d.ContainsKey($_.ParentProcessId) }
$r | ForEach-Object { Get-ProcessAndChildProcesses 0 $_ }
function Print-ProcessTree() {
function Get-ProcessAndChildProcesses($Level, $Process) {
$cmdLine = if ($Process.CommandLine -eq $null) { $Process.Name } else { $Process.CommandLine.SubString(0, [Math]::Min(200, $Process.CommandLine.Length)) }
"{0}[{1,5}] - {2}" -f (" " * $Level), $Process.ProcessId, $cmdLine
$Children = $AllProcesses | where-object {$_.ParentProcessId -eq $Process.ProcessId -and $_.CreationDate -ge $Process.CreationDate}
if ($null -ne $Children) {
foreach ($Child in $Children) {
Get-ProcessAndChildProcesses ($Level + 1) $Child
}
}
}
$AllProcesses = Get-CimInstance -ClassName "win32_process"
$RootProcesses = @()
# Process "System Idle Process" is processed differently, as ProcessId and ParentProcessId are 0
# $AllProcesses is sliced from index 1 to the end of the array
foreach ($Process in $AllProcesses[1..($AllProcesses.length-1)]) {
$Parent = $AllProcesses | where-object {$_.ProcessId -eq $Process.ParentProcessId -and $_.CreationDate -lt $Process.CreationDate}
if ($null -eq $Parent) {
$RootProcesses += $Process
}
}
# Process the "System Idle process" separately
"[{0,5}] - {1}" -f $AllProcesses[0].ProcessId, $AllProcesses[0].Name
foreach ($Process in $RootProcesses) {
Get-ProcessAndChildProcesses 0 $Process
}
}
Print-ProcessTree