src/Get-PsHandles.ps1
#requires -version 6 using namespace System.Runtime.InteropServices Set-Alias -Name pshndl -Value Get-PsHandles function Get-PsHandles { [CmdletBinding()] param( [Parameter(Mandatory, Position=0)] [ValidateScript({!!($script:ps = Get-Process -Id $_ -ErrorAction 0)})] [Int32]$Id, [Parameter()][Switch]$ShowEmpty ) begin { $kernel32, $ntdll, $page, $to_i = (New-Delegate kernel32 -Signature @{ CloseHandle = [Func[IntPtr, Boolean]] OpenProcess = [Func[UInt32, Boolean, Int32, IntPtr]] }), (New-Delegate ntdll -Signature @{ NtDuplicateObject = ( [IntPtr], [IntPtr], [IntPtr], [IntPtr].MakeByRefType(), [UInt32], [UInt32], [UInt32], [Int32] ) NtQueryInformationProcess = [Func[IntPtr, Int32, IntPtr, Int32, [Byte[]], Int32]] NtQueryObject = [Func[IntPtr, UInt32, [Byte[]], UInt32, [Byte[]], Int32]] }), [Byte[]]::new(0x1000), "ToInt$((32, 64)[($x = ($sz = [IntPtr]::Size) / 4 - 1)])" function Expand-UnicodeString([IntPtr]$h, [UInt32]$o) { if (!$ntdll.NtQueryObject.Invoke($h, $o, $page, $page.Length, $null)) { try { $uni = [GCHandle]::Alloc($page, [GCHandleType]::Pinned) $str = $uni.AddrOfPinnedObject() [Marshal]::PtrToStringUni([Marshal]::ReadIntPtr([IntPtr]($str.$to_i() + $sz))) } catch { Write-Verbose $_ } finally { if ($gch) { $gch.Free() } } } } } process { try { if (($hndl = $kernel32.OpenProcess.Invoke(0x440, $false, $Id)) -eq [IntPtr]::Zero) { throw [InvalidOperationException]::new() } $ptr = [Marshal]::AllocHGlobal(($bufsz = 0x1000)) while ($ntdll.NtQueryInformationProcess.Invoke($hndl, 51, $ptr, $bufsz, $null)) { $ptr = [Marshal]::ReAllocHGlobal($ptr, [IntPtr]($bufsz *= 2)) } $tmp = $ptr $NumberOfHandles = [Marshal]::ReadIntPtr($tmp).$to_i() $handles = (0..($NumberOfHandles - 1)).ForEach{ $HandleValue = [Marshal]::ReadIntPtr([IntPtr]($tmp.$to_i() + (0x08, 0x10)[$x])) if ($Id -ne $PID) { [IntPtr]$duple = [IntPtr]::Zero if (!$ntdll.NtDuplicateObject.Invoke( $hndl, $HandleValue, [IntPtr]-1, [ref]$duple, 0, 0, 0x02 )) { $tmp = [IntPtr]($tmp.$to_i() + (28, 40)[$x]) continue } $page.Clear() $type = Expand-UnicodeString $duple 2 $page.Clear() $name = Expand-UnicodeString $duple 1 if ($duple -ne [IntPtr]::Zero) { if (!$kernel32.CloseHandle.Invoke($duple)) { Write-Verbose "Could not close duple of $($HandleValue.$to_i()) handle." } } } else { $page.Clear() $type = Expand-UnicodeString $HandleValue 2 $page.Clear() $name = Expand-UnicodeString $HandleValue 1 } [PScustomObject]@{ Value = '0x{0:X}' -f $HandleValue Type = $type Name = $name } $tmp = [IntPtr]($tmp.$to_i() + (28, 40)[$x]) } } catch { Write-Verbose $_ } finally { if ($ptr) { [Marshal]::FreeHGlobal($ptr) } if ($hndl -and $hndl -ne [IntPtr]::Zero) { if (!$kernel32.CloseHandle.Invoke($hndl)) { Write-Verbose "Could not close process handle." } } } } end { $ps.Dispose() if ($handles) { if (!$ShowEmpty) { $handles.Where{$_.Name} } else { $handles } } [GC]::Collect() } } |