src/Get-PsCmdline.ps1
#requires -version 6 using namespace System.ComponentModel using namespace System.Runtime.InteropServices Set-Alias -Name pscmd -Value Get-PsCmdline function Get-PsCmdline { [CmdletBinding(DefaultParameterSetName='Name')] param( [Parameter(Mandatory, ParameterSetName='Name', Position=0)] [ValidateNotNullOrEmpty()] [ValidateScript({!!($script:ps = Get-Process $_ -ErrorAction 0)})] [String]$Name, [Parameter(Mandatory, ParameterSetName='Id', Position=0)] [ValidateScript({!!($script:ps = Get-Process -Id $_ -ErrorAction 0)})] [Int32]$Id ) process { $ntdll = New-Delegate ntdll -Signature @{ NtQueryInformationProcess = [Func[IntPtr, Int32, [Byte[]], Int32, [Byte[]], Int32]] RtlNtStatusToDosError = [Func[Int32, Int32]] } $ps.ForEach{ if ($_.Handle) { $req, $to_i = [Byte[]]::new(4), "ToInt$((32, 64)[($sz = [IntPtr]::Size) / 4 - 1])" if (( $nts = $ntdll.NtQueryInformationProcess.Invoke($_.Handle, 60, $null, 0, $req) ) -ne 0xC0000004) { Write-Verbose "PID ($_.Id): $([Win32Exception]::new( $ntdll.RtlNtStatusToDosError.Invoke($nts) ).Message)" continue } $buf = [Byte[]]::new([BitConverter]::ToUInt32($req, 0)) if (( $nts = $ntdll.NtQueryInformationProcess.Invoke($_.Handle, 60, $buf, $buf.Length, $null) ) -ne 0) { Write-Verbose "PID ($_.Id): $([Win32Exception]::new( $ntdll.RtlNtStatusToDosError.Invoke($nts) ).Message)" continue } $gch = [GCHandle]::Alloc($buf, [GCHandleType]::Pinned) $ptr = $gch.AddrOfPinnedObject() $cmd = [Marshal]::PtrToStringUni([Marshal]::ReadIntPtr([IntPtr]($ptr.$to_i() + $sz))) $gch.Free() [PSCustomObject]@{ ProcessName = $_.ProcessName PID = $_.Id CommandLine = $cmd } } else { Write-Verbose "PID $($_.Id): could not retrieve required information." } $_.Dispose() } # foreach [GC]::Collect() } } |