usr/Get-PsTree.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
Set-Alias -Name pstree -Value Get-PsTree
function Get-PsTree {
  [CmdletBinding()]param()

  begin {
    New-Structure tagPROCESSENTRY32W {
      UInt32  dwSize
      UInt32  cntUsage
      UInt32  th32ProcessID
      UIntPtr th32DefaultHeapID
      UInt32  th32ModuleID
      UInt32  cntThreads
      UInt32  th32ParentProcessID
      Int32   pcPriClassBase
      UInt32  dwFlags
      String 'szExeFile ByValTStr 260'
    } -CharSet Unicode
    $out_ = [tagPROCESSENTRY32W].MakeByRefType()

    New-Delegate kernel32 {
      bool CloseHandle([ptr])
      ptr  CreateToolhelp32Snapshot([uint, uint])
      bool Process32FirstW([ptr, _out_])
      bool Process32NextW([ptr, _out_])
    }

    function Add-PsChild([PSCustomObject]$Process, [Int32]$Depth = 1) {
      end {
        $lst.Where{$_.PPID -eq $Process.PID -and $_.PPID -ne 0}.ForEach{
          "$("$([Char]32)" * 2 * $Depth)$($_.Name) ($($_.PID))"
          Add-PsChild $_ (++$Depth)
          $Depth--
        }
      }
    }
  }
  process {}
  end {
    try {
      $hndl = $kernel32.CreateToolhelp32Snapshot.Invoke(0x02, 0)
      $out = [tagPROCESSENTRY32W]::new()
      $out.dwSize = [tagPROCESSENTRY32W]::GetSize()
      if (!$kernel32.Process32FirstW.Invoke($hndl, [ref]$out)) {
        throw [InvalidOPerationException]::new('Cannot retrieve process information.')
      }
      $lst = do {
        [PSCustomObject]@{
          PID  = $out.th32ProcessID
          PPID = $out.th32ParentProcessID
          Name = $out.szExeFile
        }
      } while ($kernel32.Process32NextW.Invoke($hndl, [ref]$out))
      $lst.ForEach{
        if (!($ps = Get-Process -Id $_.PPID -ErrorAction 0) -or !$ps.Name -or $_.PPID -eq 0) {
          "$($_.Name) ($($_.PID))"
          Add-PsChild $_
        }
      }
    }
    catch { Write-Verbose $_ }
    finally {
      if ($hndl) {
        if (!$kernel32.CloseHandle.Invoke($hndl)) {
          throw [InvalidOPerationException]::new('Cannot release processes snapshot.')
        }
      }
    }
  }
}

Export-ModuleMember -Alias pstree -Function Get-PsTree