Reputation: 777
In PowerShell, using Get-WmiObject win32_process
it is possible to get the command-line arguments of any active process in windows (like this). How do you do the same in Linux and/or OSX?
The ps
command can do this to be sure, but I am looking for a PowerShell-native solution in order to be able to maintain strong typing.
Upvotes: 2
Views: 1103
Reputation: 438123
Note: As of PowerShell Core 7.1.0-rc.2, a new-for-7.1 .CommandLine
ETS script property exists that determines the command line on Windows and on Linux.
However:
The solution detailed in the bottom section works on macOS (and at least on some Linux distros too), and can easily be integrated into the .CommandLine
property as follows - you can do this even in earlier PowerShell [Core] versions, and even in Windows PowerShell:
# Run this once per session to add a / update the .CommandLine property
# on System.Diagnostics.Process to report the process' command line
# on Windows, Linux, and macOS
Update-TypeData -Force -Value {
if ($env:OS -eq 'Windows_NT') {
(Get-CimInstance Win32_Process -Filter "ProcessId = $($this.Id)").CommandLine
} elseif ($IsLinux) {
(Get-Content -LiteralPath "/proc/$($this.Id)/cmdline") -replace "`0", ' '
} elseif ($IsMacOs) {
ps -o command= $this.Id
}
} -TypeName System.Diagnostics.Process -MemberName CommandLine -MemberType ScriptProperty
Once enabled, you can use it as follows:
$pidOfInterest = $PID # use the PowerShell session's own as an example
(Get-Process -Id $pidOfInterest).CommandLine
Note:
Unlike on Windows, on Unix platforms the command line reported is not a faithful representation of the original command line; notably, argument boundaries originally enforced by single- or double-quoting are lost:
Note: On Unix-like platforms, processes receive no command line that they themselves must parse (as is unfortunately the case on Windows); instead, they receive an array of verbatim arguments. Thus, there is no original command line as such, only the shell-specific command line that was passed to the original shell, which then translated that into the array of verbatim arguments passed to the process on creation.
On macOS, the ps
-based solution detailed below provides no information about the original argument boundaries and simply joins the verbatim argument with spaces, so the resulting command-line string cannot generally be expected to work like the original invocation.
On Linux, the special /proc/<pid>/cmdline
files do preserve the original argument boundaries, simply by using NUL
characters (0x0
) rather than spaces to join the verbatim arguments; however, it would require a nontrivial effort to reconstruct a working command line from that (notably the need to recreate quoting and escaping as necessary), and even that presents a conceptual challenge: what shell do you reconstruct the command line for, given that PowerShell's syntax differs from Bash's, for instance? Therefore, the command above also simply joins the verbatim arguments with spaces on Linux, the same way that ps
does on macOS.
Accessing the .CommandLine
property is costly in terms of performance, because it invokes a CIM/WMI call on Windows, and running an external executable in a child process on Unix.
On macOS, you can use the standard ps
utility[1] as follows, but note that the command line it returns lacks the original quoting:
# Print the command line used to invoke this PowerShell session,
# represented by automatic variable $PID.
# Note that $PID is just an *example* PID (process identifier).
ps -o command= $PID
Note: command
is a nonstandard variant of the args
field name that isn't subject to the latter's limit of 64 chars., and it is supported on both Linux and macOS.
To illustrate the quoting issue:
The following command (executed from PowerShell):
pwsh -noprofile -noexit -c "'hi there'; ps -o command= `$PID"
outputs a string such as:
/usr/local/bin/pwsh -noprofile -noexit -c 'hi there'; ps -o command= $PID
Note how the "..."
quoting enclosing the original -c
argument was lost.
[1] The superior Linux-specific alternative is Get-Content -LiteralPath /proc/$PID/cmdline
, which has the advantage of separating the arguments with NUL
characters in order to preserve the original argument boundaries - but to see those boundaries extra work is needed. The ps
solution works on at least some Linux distros too, but it is conceivable that there are ps
implementation in use that do not support the command
field. Either way, the ps
solution lacks information about the original argument boundaries.
Upvotes: 5