pwsh/Get-PsHandle.ps1

using namespace System.Runtime.InteropServices

Set-Alias -Name pshandle -Value Get-PsHandle
function Get-PsHandle {
  [CmdletBinding()]param($PSBoundParameters)

  begin {
    New-Delegate kernel32 {
      bool CloseHandle([ptr])
    }

    New-Delegate ntdll {
      int NtDuplicateObject([ptr, ptr, ptr, ptr_, uint, bool, uint])
      int NtQueryInformationProcess([ptr, uint, ptr, uint, buf])
      int NtQueryObject([ptr, uint, buf, uint, buf])
    }

    $to_i = "ToInt$((32, 64)[($x = ($sz = [IntPtr]::Size) / 4 - 1)])"
    $page = [Byte[]]::new(0x1000)
    function Expand-UniString([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([ptr].Mov($str, $sz)))
        }
        catch { Write-Verbose $_ }
        finally { if ($uni) { $uni.Free() } }
      }
    }
  }
  process {}
  end {
    New-PsProxy $PSBoundParameters -Callback {
      try {
        $ptr = [Marshal]::AllocHGlobal(($bufsz = 0x1000))
        while ($ntdll.NtQueryInformationProcess.Invoke($_.Handle, 51, $ptr, $bufsz, $null)) {
          $ptr = [Marshal]::ReAllocHGlobal($ptr, [IntPtr]($bufsz *= 2))
        }

        $tmp, $hndl = $ptr, $_.Handle
        $handles = (0..([Marshal]::ReadIntPtr($tmp).$to_i() - 1)).ForEach{
          $HandleValue = [Marshal]::ReadIntPtr([ptr].Mov($tmp, (0x08, 0x10)[$x]))
          [IntPtr]$duple = [IntPtr]::Zero
          if ($ntdll.NtDuplicateObject.Invoke(
            $hndl, $HandleValue, [IntPtr]-1, [ref]$duple, 0, $false, 0x02
          ) -eq 0) {
            $page.Clear()
            $__type = Expand-UniString $duple 2
            $page.Clear()
            $__name = Expand-UniString $duple 1

            if (!$kernel32.CloseHandle.Invoke($duple)) {
              Write-Verbose "Cannot close $($duple.$to_i()) duple."
            }

            [PSCustomObject]@{
              Value = '0x{0:X}' -f $HandleValue.$to_i()
              Type  = $__type
              Name  = $__name
            }
          }

          $tmp = [ptr].Mov($tmp, (0x1C, 0x28)[$x])
        }
      }
      catch { Write-Verbose $_ }
      finally { if ($ptr) { [Marshal]::FreeHGlobal($ptr) } }

      if ($handles) { $handles.Where{![String]::IsNullOrEmpty($_.Name)} }
    } # proxy
  }
}

Export-ModuleMember -Alias pshandle -Function Get-PsHandle