src/Get-PsDump.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
#requires -version 6
using namespace System.IO
using namespace System.Text
using namespace Microsoft.Win32.SafeHandles

Set-Alias -Name psdump -Value Get-PsDump
function Get-PsDump {
  [CmdletBinding()]
  param(
    [Parameter(Mandatory, Position=0)]
    [ValidateScript({!!($script:ps = Get-Process -Id $_ -ErrorAction 0)})]
    [Int32]$Id,

    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [ValidateSet('MiniDump', 'FullDump')]
    [String]$DumpType = 'MiniDump',

    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [ValidateScript({Test-Path $_})]
    [String]$SavePath = $pwd.Path
  )

  begin {
    $kernel32, $dmp = (New-Delegate kernel32 -Signature @{
      LoadLibraryW = [Func[[Byte[]], IntPtr]]
      FreeLibrary = [Func[IntPtr, Boolean]]
    }), "${SavePath}\$($ps.Name)_${Id}.dmp"
  }
  process {}
  end {
    try {
      if (!($dll = $kernel32.LoadLibraryW.Invoke(
        [Encoding]::Unicode.GetBytes('dbghelp.dll')
      ))) { throw [DllNotFoundException]::new() }

      $dbghelp, $fs, $numeric = (New-Delegate dbghelp -Signature @{
        MiniDumpWriteDump =
          [Func[IntPtr, UInt32, SafeFileHandle, UInt32, IntPtr, IntPtr, IntPtr, Boolean]]
      }), [File]::Create($dmp), (6, 261)[$DumpType -eq 'MiniDump']

      if (!$dbghelp.MiniDumpWriteDump.Invoke(
        $ps.Handle, ${Id}, $fs.SafeFileHandle, $numeric,
        [IntPtr]::Zero, [IntPtr]::Zero, [IntPtr]::Zero
      )) {
        $err = $true
        throw [InvalidOperationException]::new()
      }
    }
    catch { Write-Verbose $_ }
    finally {
      if ($fs) { $fs.Dispose() }
      if ($dll) {
        if (!$kernel32.FreeLibrary.Invoke($dll)) {
          Write-Verbose 'Could not release dbghelp.dll library.'
        }
      }
      if ($err) { Remove-Item $dmp -Force -ErrorAction 0 }
    }

    $ps.Dispose()
  }
}