Handle.ps1
<#
.Synopsis Gets open system handles. .DESCRIPTION Gets open system handles. This cmdlet can filter by process and handle name. .EXAMPLE Get-Process Notepad | Get-Handle .EXAMPLE Get-Handle -Name "*myfile.txt" #> function Get-Handle { [CmdletBinding()] param( # A process to return open handles for. [Parameter(ValueFromPipeline=$true)] [System.Diagnostics.Process]$Process, # The name of the handle [Parameter()] [String]$Name = $null, [Parameter()] [ValidateSet("File", "Directory")] [String]$Type = $null ) Begin { #$Handles = } Process { Get-AllHandles #if ($Process -ne $Null) #{ # $Handles | Where-Object { $_.ProcessId -eq $Process.Id -and $_.Name -match $Name} #} #elseif ($Name -ne $null) #{ # $Handles | Where-Object { $_.Name -like $Name} #} #else #{ # $Handles #} } } <# .Synopsis Closes open system handles. .DESCRIPTION Closes open system handles. This cmdlet can cause system instability. .EXAMPLE Get-Process Notepad | Get-Handle | Close-Handle .EXAMPLE Get-Handle -Name "*myfile.txt" | Close-Handle #> function Close-Handle { [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='High')] param( [Parameter(ValueFromPipeline=$true)] $Handle ) Process { if ($PSCmdlet.ShouldProcess($Handle.Name,"Closing a handle can cause system instability. Close handle?")) { $Handle.Close() } } } <# .SYNOPSIS Converts a DOS-style file name into a regular Windows file name. .DESCRIPTION This function can convert a DOS-style (\Device\HarddiskVolume1\MyFile.txt) file name into a regular Windows (C:\MyFile.txt) file name. .PARAMETER RawFileName The DOS-style file name. .EXAMPLE ConvertTo-RegularFileName -RawFileName "\Device\HarddiskVolume1\MyFile.txt" #> function ConvertTo-RegularFileName { param($RawFileName) foreach ($logicalDrive in [Environment]::GetLogicalDrives()) { $targetPath = New-Object System.Text.StringBuilder 256 if ([PoshInternals.Kernel32]::QueryDosDevice($logicalDrive.Substring(0, 2), $targetPath, 256) -eq 0) { return $targetPath } $targetPathString = $targetPath.ToString() if ($RawFileName.StartsWith($targetPathString)) { $RawFileName = $RawFileName.Replace($targetPathString, $logicalDrive.Substring(0, 2)) break } } $RawFileName } <# .SYNOPSIS Converts a SystemHandleEntry into a PSCustomObject. .DESCRIPTION This function is intended to convert a SystemHandleEntry returned by Get-FileHandle into a PSCustomObject that exposes a Process property and a file name. .PARAMETER HandleEntry The SystemHandleEntry as returned by Get-FileHandle .EXAMPLE Get-FileHandle | ConvertTo-HandleHashTable #> function ConvertTo-HandleHashTable { [CmdletBinding()] param( [Parameter(Mandatory, ValueFromPipeline=$true)] $HandleEntry, [Parameter(Mandatory)] [IntPtr]$ProcessHandle ) Process { if ($HandleEntry.GrantedAccess -eq 0x0012019f -or $HandleEntry.GrantedAccess -eq 0x00120189 -or $HandleEntry.GrantedAccess -eq 0x120089) { return } $HandleType = Find-HandleType -HandleEntry $HandleEntry -ProcessHandle $ProcessHandle $length = 0 $Result = [PoshInternals.NtDll]::NtQueryObject($ProcessHandle, 'ObjectNameInformation', [IntPtr]::Zero, 0, [ref]$length) $ptr = [IntPtr]::Zero if ($Result -ne [PoshInternals.NT_STATUS]::STATUS_INFO_LENGTH_MISMATCH) { return } try { $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal($length) if ([PoshInternals.NtDll]::NtQueryObject($ProcessHandle, 'ObjectNameInformation', $ptr, $length, [ref]$length) -ne [PoshInternals.NT_STATUS]::STATUS_SUCCESS) { return } $Path = [Runtime.InteropServices.Marshal]::PtrToStringUni([IntPtr]([long]$ptr + 2 * [IntPtr]::Size)) if ($HandleType -eq "File" -or $HandleType -eq "Directory") { $Path = ConvertTo-RegularFileName $Path } $PsObject = [PSCustomObject]@{ Type=$HandleType; Path=$Path; Process=$HandleEntry.OwnerProcessId; } return $PsObject } catch { Write-Warning $_.Exception.Message } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) } } } $HandleTypeCache = @{} function Find-HandleType { param( [Parameter(Mandatory)] $HandleEntry, [Parameter(Mandatory)] [IntPtr]$ProcessHandle) if ($HandleTypeCache.ContainsKey($HandleEntry.ObjectTypeNumber)) { return $HandleTypeCache[$HandleEntry.ObjectTypeNumber] } $length = 0 $Result = [PoshInternals.NtDll]::NtQueryObject($ProcessHandle, 'ObjectTypeInformation', [IntPtr]::Zero, 0, [ref] $length) $ptr = [IntPtr]::Zero if ($Result -ne [PoshInternals.NT_STATUS]::STATUS_INFO_LENGTH_MISMATCH) { return } try { $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal($length) if ([PoshInternals.NtDll]::NtQueryObject($ProcessHandle, 'ObjectTypeInformation', $ptr, $length, [ref] $length) -ne [PoshInternals.NT_STATUS]::STATUS_SUCCESS) { return } $typeStr = [Runtime.InteropServices.Marshal]::PtrToStringUni([IntPtr]([long]$ptr + 0x58 + 2 * [IntPtr]::Size)) $HandleTypeCache[$HandleEntry.ObjectTypeNumber] = $typeStr $typeStr } catch { Write-Warning $_.Exception.Message } finally { [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) } } <# .SYNOPSIS Returns open file handles found on the system. .DESCRIPTION This function returns all open file handles found on the system. In its current state this cmdlet will only work on a Windows 8 machine. .EXAMPLE Get-Handle #> function Get-AllHandles { param($Type) $length = 0x10000 $ptr = [IntPtr]::Zero try { while ($true) { $ptr = [Runtime.InteropServices.Marshal]::AllocHGlobal($length) $wantedLength = 0 [PoshInternals.SYSTEM_INFORMATION_CLASS]$HandleInfo = 'SystemHandleInformation' $result = [PoshInternals.NtDll]::NtQuerySystemInformation($HandleInfo, $ptr, $length, [ref] $wantedLength) if ($result -eq [PoshInternals.NT_STATUS]::STATUS_INFO_LENGTH_MISMATCH) { $length = [Math]::Max($length, $wantedLength) [Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) $ptr = [IntPtr]::Zero } elseif ($result -eq [PoshInternals.NT_STATUS]::STATUS_SUCCESS) { break } else { throw (New-Object System.ComponentModel.Win32Exception) } } if ([IntPtr]::Size -eq 4) { $handleCount = [Runtime.InteropServices.Marshal]::ReadInt32($ptr) } else { $handleCount = [Runtime.InteropServices.Marshal]::ReadInt64($ptr) } $She = New-Object -TypeName PoshInternals.SystemHandleEntry $size = [Runtime.InteropServices.Marshal]::SizeOf($She) $CurrentProcessHandle = (Get-Process -Id $Pid).Handle $ClassName = "StructArray$(Get-Random -Minimum 1 -Maximum 10000)" $StructName = "Struct$(Get-Random -Minimum 1 -Maximum 10000)" Add-Type -TypeDefinition " using System.Runtime.InteropServices; [StructLayout(LayoutKind.Sequential)] public struct $StructName { public int OwnerProcessId; public byte ObjectTypeNumber; public byte Flags; public ushort Handle; public System.IntPtr Object; public int GrantedAccess; } [StructLayout(LayoutKind.Sequential)] public struct $ClassName { [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = $HandleCount, ArraySubType = UnmanagedType.Struct)] public $StructName [] Entries; } " $HandleArray = New-Object -TypeName $ClassName $HandleArray = [Runtime.InteropServices.Marshal]::PtrToStructure([IntPtr]([long]$ptr + [IntPtr]::Size), [Type]$HandleArray.GetType()) for ($i = 0; $i -lt $handleCount; $i++) { $HandleEntry = $HandleArray.Entries[$i] $sourceProcessHandle = [IntPtr]::Zero $handleDuplicate = [IntPtr]::Zero $sourceProcessHandle = [PoshInternals.Kernel32]::OpenProcess(0x40, $true, $HandleEntry.OwnerProcessId) if ($sourceProcessHandle -eq [IntPtr]::Zero) { continue } if (-not [PoshInternals.Kernel32]::DuplicateHandle($sourceProcessHandle, [IntPtr]$HandleEntry.Handle, $CurrentProcessHandle, [ref]$handleDuplicate, 0, $false, 2)) { continue } $HandleEntry | ConvertTo-HandleHashTable -ProcessHandle $handleDuplicate } } finally { if ($ptr -ne [IntPtr]::Zero) { [System.Runtime.InteropServices.Marshal]::FreeHGlobal($ptr) } } } |