usr/lib/Get-PipeList.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
73
74
75
76
77
78
79
80
81
82
83
using namespace System.Runtime.InteropServices

Set-Alias -Name pipelist -Value Get-PipeList
function Get-PipeList {
  [CmdletBinding()]param()

  begin {
    New-Delegate kernel32 {
      sfh CreateFileW([buf, int, IO.FileShare, ptr, IO.FileMode, int, ptr])
    }

    New-Delegate ntdll {
      int NtQueryDirectoryFile([sfh, ptr, ptr, ptr, buf, ptr, uint, uint, bool, ptr, bool])
    }

    New-Structure LARGE_INTEGER {
      Int64  'QuadPart 0'
      UInt32 'LowPart 0'
      Int32  'iLowPart 0'
      Int32  'HighPart 4'
      UInt32 'dwHighPart 4'
    } -Explicit -PackingSize Size8

    New-Structure FILE_DIRECTORY_INFORMATION {
      UInt32 NextEntryOffset
      UInt32 FileIndex
      LARGE_INTEGER CreationTime
      LARGE_INTEGER LastAccessTime
      LARGE_INTEGER LastWriteTime
      LARGE_INTEGER ChangeTime
      LARGE_INTEGER EndOfFile
      LARGE_INTEGER AllocationSize
      UInt32 FileAttributes
      UInt32 FileNameLength
      String 'FileName ByValTStr 1'
    } -CharSet Unicode
  }
  process {}
  end {
    if (($pipes = $kernel32.CreateFileW.Invoke(
      [buf].Uni('\\.\pipe\'), 0x80000000, [IO.FileShare]::Read,
      [IntPtr]::Zero, [IO.FileMode]::Open, 0, [IntPtr]::Zero
    )).IsInvalid) {
      throw [InvalidOperationException]::new('\\.\pipe\ is unavailable.')
    }

    $query, $isb = $true, [Byte[]]::new([IntPtr]::Size * 2) # IO_STATUS_BLOCK
    try {
      $dir = [Marshal]::AllocHGlobal(0x1000)
      while (1) {
        if ($ntdll.NtQueryDirectoryFile.Invoke(
          $pipes, [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero,
          $isb, $dir, 0x1000, 1, $false, [IntPtr]::Zero, $query
        ) -ne 0) {break}

        $tmp = $dir."ToInt$([IntPtr]::Size * 8)"()
        while (1) {
          $fdi = [IntPtr]$tmp -as [FILE_DIRECTORY_INFORMATION]
          [PSCustomObject]@{
            PipeName = [Marshal]::PtrToStringUni(
              [IntPtr]($tmp + $fdi::OfsOf('FileName')), $fdi.FileNameLength / 2
            )
            Instances = $fdi.EndOfFile.LowPart
            MaxInstances = $fdi.AllocationSize.iLowPart
          }

          if (!$fdi.NextEntryOffset) {break}
          $tmp += $fdi.NextEntryOffset
        }

        $query = $false
      }
    }
    catch { Write-Verbose $_ }
    finally { if ($dir) {[Marshal]::FreeHGlobal($dir)}}

    $pipes.Dispose()
    Write-Verbose "$($pipes.IsClosed)"
  }
}

Export-ModuleMember -Alias pipelist -Function Get-PipeList