Cmdlets/Out-MiniDump.ps1

# ? TITEL Out-MiniDump
# ? DESCRIPTION
# ? TAGS UserCmdlet
# ? VERSION 2019.09.09

using Module Microsoft.PowerShell.Management
using Module Microsoft.PowerShell.Utility
using namespace System
using namespace System.Runtime.InteropServices
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
Set-StrictMode -Version Latest

function Out-MiniDump {
    <#
        .SYNOPSIS
        Generates a full-memory minidump of a process.
 
        .DESCRIPTION
        Out-Minidump writes a process dump file with all process memory to disk.
 
        .PARAMETER Process
        Specifies the process for which a dump will be generated. The process object
        is obtained with Get-Process.
 
        .PARAMETER DumpFilePath
        Specifies the path where dump files will be written. By default, dump files
        are written to the current working directory. Dump file names take following
        form: processname_id.dmp
 
        .EXAMPLE
        Out-Minidump -Process (Get-Process -Id 4293)
 
        .EXAMPLE
        Get-Process lsass | Out-Minidump
 
        .EXAMPLE
        Get-Process | Out-Minidump -DumpFilePath C:\temp
 
        .INPUTS
        System.Diagnostics.Process
        You can pipe a process object to Out-Minidump.
 
        .OUTPUTS
        System.IO.FileInfo
    #>


    [CmdletBinding()]
    Param (
        [Parameter(Position          = 0,
                   Mandatory         = $True, 
                   ValueFromPipeline = $True)]
        [System.Diagnostics.Process]
        $Process,

        [Parameter(Position = 1)]
        [ValidateScript({ Test-Path $_ })]
        [String]
        $DumpFilePath = $PWD
    )

    BEGIN {
        $WER = [PSObject].Assembly.GetType('System.Management.Automation.WindowsErrorReporting')
        $WERNativeMethods = $WER.GetNestedType('NativeMethods', 'NonPublic')
        $Flags = [Reflection.BindingFlags] 'NonPublic, Static'
        $MiniDumpWriteDump = $WERNativeMethods.GetMethod('MiniDumpWriteDump', $Flags)
        $MiniDumpWithFullMemory = [UInt32] 2
    }

    PROCESS {
        $ProcessId = $Process.Id
        $ProcessName = $Process.Name
        $ProcessHandle = $Process.Handle
        $ProcessFileName = "$($ProcessName)_$($ProcessId).dmp"

        $ProcessDumpPath = Join-Path $DumpFilePath $ProcessFileName

        $FileStream = New-Object IO.FileStream($ProcessDumpPath, [IO.FileMode]::Create)

        $Result = $MiniDumpWriteDump.Invoke($null, @($ProcessHandle,
                                                     $ProcessId,
                                                     $FileStream.SafeFileHandle,
                                                     $MiniDumpWithFullMemory,
                                                     [IntPtr]::Zero,
                                                     [IntPtr]::Zero,
                                                     [IntPtr]::Zero))

        $FileStream.Close()

        if (-not $Result) {
            $Exception = New-Object ComponentModel.Win32Exception
            $ExceptionMessage = "$($Exception.Message) ($($ProcessName):$($ProcessId))"

            # Remove any partially written dump files. For example, a partial dump will be written
            # in the case when 32-bit PowerShell tries to dump a 64-bit process.
            Remove-Item $ProcessDumpPath -ErrorAction SilentlyContinue

             Write-Error -Exception $ExceptionMessage
        }
        else {
            Get-ChildItem $ProcessDumpPath
        }
    }

    END {}
}