Get-Process , , , Microsoft , . PowerShell , , , PowerShell', - , , , . : PowerShell, ProcessExplorer, pslist? -, GUI , -, , PowerShell ? . , , , ! - WMI, , - , , . , . , , , PID, PPID. , Windows : , WMI NtQuerySystemInformation. ( ) , NtQuerySystemInformation, , . Vim ( ) : Set-Variable ($$ = [Regex].Assembly.GetType( 'Microsoft.Win32.NativeMethods' ).GetMethod('NtQuerySystemInformation')).Name $$ , $NtQuerySystemInformation. SYSTEM_PROCESS_INFORMATION, Win7 x86 : +0x000 NextEntryOffset : Uint4B +0x004 NumberOfThreads : Uint4B +0x008 WorkingSetPrivateSize : _LARGE_INTEGER +0x010 HardFaultCount : Uint4B +0x014 NumberOfThreadsHighWatermark : Uint4B +0x018 CycleTime : Uint8B +0x020 CreateTime : _LARGE_INTEGER +0x028 UserTime : _LARGE_INTEGER +0x030 KernelTime : _LARGE_INTEGER +0x038 ImageName : _UNICODE_STRING +0x040 BasePriority : Int4B +0x044 UniqueProcessId : Ptr32 Void +0x048 InheritedFromUniqueProcessId : Ptr32 Void +0x04c HandleCount : Uint4B +0x050 SessionId : Uint4B +0x054 UniqueProcessKey : Uint4B +0x058 PeakVirtualSize : Uint4B +0x05c VirtualSize : Uint4B +0x060 PageFaultCount : Uint4B +0x064 PeakWorkingSetSize : Uint4B +0x068 WorkingSetSize : Uint4B +0x06c QuotaPeakPagedPoolUsage : Uint4B +0x070 QuotaPagedPoolUsage : Uint4B +0x074 QuotaPeakNonPagedPoolUsage : Uint4B +0x078 QuotaNonPagedPoolUsage : Uint4B +0x07c PagefileUsage : Uint4B +0x080 PeakPagefileUsage : Uint4B +0x084 PrivatePageCount : Uint4B +0x088 ReadOperationCount : _LARGE_INTEGER +0x090 WriteOperationCount : _LARGE_INTEGER +0x098 OtherOperationCount : _LARGE_INTEGER +0x0a0 ReadTransferCount : _LARGE_INTEGER +0x0a8 WriteTransferCount : _LARGE_INTEGER +0x0b0 OtherTransferCount : _LARGE_INTEGER NextEntryOffset, ImageName, UniqueProcessId InheritedFromUniqueProcessId, Marshal. : if (($ta = [PSObject].Assembly.GetType( 'System.Management.Automation.TypeAccelerators' ))::Get.Keys -notcontains 'Marshal') { $ta::Add('Marshal', [Runtime.InteropServices.Marshal]) } $ret = 0 try { # $ptr = [Marshal]::AllocHGlobal(1024) if ($NtQuerySystemInformation.Invoke($null, ( $par = [Object[]]@(5, $ptr, 1024, $ret) )) -eq 0xC0000004) { #STATUS_INFO_LENGTH_MISMATCH $ptr = [Marshal]::ReAllocHGlobal($ptr, [IntPtr]$par[3]) if ($NtQuerySystemInformation.Invoke($null, ( $par = [Object[]]@(5, $ptr, $par[3], 0) )) -ne 0) { throw New-Object InvalidOperationException('- ...') } } } catch { $_.Exception } finally { if ($ptr -ne $null) { [Marshal]::FreeHGlobal($ptr) } } , . ! ImageName UNICODE_STRING, ? : $UNICODE_STRING = [Activator]::CreateInstance( [Object].Assembly.GetType( 'Microsoft.Win32.Win32Native+UNICODE_STRING' ) ) . $len = [Marshal]::SizeOf($UNICODE_STRING) - 1 $tmp = $ptr $Processes = while (($$ = [Marshal]::ReadInt32($tmp))) #NextEntryOffset [Byte[]]$bytes = 0..$len{ [Marshal]::ReadByte($tmp, $ofb) $ofb++ } # UNICODE_STRING $gch = [Runtime.InteropServices.GCHandle]::Alloc($bytes, 'Pinned') $uni = [Marshal]::PtrToStructure( $gch.AddrOfPinnedObject(), [Type]$UNICODE_STRING.GetType() ) $gch.Free() New-Object PSObject -Property @{ ProcessName = if ([String]::IsNullOrEmpty(( $proc = $uni.GetType().GetField( 'Buffer', [Reflection.BindingFlags]36 ).GetValue($uni)) )) { 'Idle' } else { $proc } PID = [Marshal]::ReadInt32($tmp, 0x44) PPID = [Marshal]::ReadInt32($tmp, 0x48) } $tmp = [IntPtr]($tmp.ToInt32() + $$) } $Processes PSObject, . , , . function Get-ProcessChild { param( > . , , . #function Get-ProcessTree { <# .NOTES .Where .ForEach PS -lt v5 #> begin { Set-Variable ($$ = [Regex].Assembly.GetType( 'Microsoft.Win32.NativeMethods' ).GetMethod('NtQuerySystemInformation')).Name $$ $UNICODE_STRING = [Activator]::CreateInstance( [Object].Assembly.GetType( 'Microsoft.Win32.Win32Native+UNICODE_STRING' ) ) function Get-ProcessChild { param( System.Management.Automation.TypeAccelerators' ))::Get.Keys -notcontains 'Marshal') { $ta::Add('Marshal', [Runtime.InteropServices.Marshal]) } } process { try { $ret = 0 $ptr = [Marshal]::AllocHGlobal(1024) if ($NtQuerySystemInformation.Invoke($null, ( $par = [Object[]]@(5, $ptr, 1024, $ret) )) -eq 0xC0000004) { #STATUS_INFO_LENGTH_MISMATCH $ptr = [Marshal]::ReAllocHGlobal($ptr, [IntPtr]$par[3]) if (($nts = $NtQuerySystemInformation.Invoke($null, ( $par = [Object[]]@(5, $ptr, $par[3], 0) ))) -ne 0) { throw New-Object InvalidOperationException( 'NTSTATUS: 0x{0:X}' -f $nts ) } } $len = [Marshal]::SizeOf($UNICODE_STRING) - 1 $tmp = $ptr $Processes = while (($$ = [Marshal]::ReadInt32($tmp))) ForEach-Object $ofb = 0x38{ [Marshal]::ReadByte($tmp, $ofb) $ofb++ } $gch = [Runtime.InteropServices.GCHandle]::Alloc($bytes, 'Pinned') $uni = [Marshal]::PtrToStructure( $gch.AddrOfPinnedObject(), [Type]$UNICODE_STRING.GetType() ) $gch.Free() New-Object PSObject -Property @{ ProcessName = if ([String]::IsNullOrEmpty(( $proc = $uni.GetType().GetField( 'Buffer', [Reflection.BindingFlags]36 ).GetValue($uni)) )) { 'Idle' } else { $proc } PID = [Marshal]::ReadInt32($tmp, 0x44) PPID = [Marshal]::ReadInt32($tmp, 0x48) } $tmp = [IntPtr]($tmp.ToInt32() + $$) } } catch { $_.Exception } finally { if ($ptr -ne $null) { [Marshal]::FreeHGlobal($ptr) } } } end { if ($Processes -eq $null) { break } $Processes | Where-Object { -not (Get-Process -Id $_.PPID -ea 0) -or $_.PPID -eq 0 } | ForEach-Object { "$($_.ProcessName) ($($_.PID))" Get-ProcessChild $_ } [void]$ta::Remove('Marshal') } #}