在 PowerShell 中,使用Get-WmiObject win32_process
它可以获得 Windows 中任何活动进程的命令行参数(像这样)。你如何在 Linux 和/或 OSX 中做同样的事情?
该ps
命令可以肯定地做到这一点,但我正在寻找一种 PowerShell 原生解决方案,以便能够保持强类型。
在 PowerShell 中,使用Get-WmiObject win32_process
它可以获得 Windows 中任何活动进程的命令行参数(像这样)。你如何在 Linux 和/或 OSX 中做同样的事情?
该ps
命令可以肯定地做到这一点,但我正在寻找一种 PowerShell 原生解决方案,以便能够保持强类型。
注意:从 PowerShell Core 7.1.0-rc.2 开始,存在一个 new-for-7.1 .CommandLine
ETS 脚本属性,用于确定 Windows 和Linux上的命令行。然而:
底部详述的解决方案适用于 macOS(至少也适用于某些 Linux 发行版),并且可以轻松集成到.CommandLine
属性中,如下所示 - 即使在早期的 PowerShell [Core] 版本中,甚至在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
启用后,您可以按如下方式使用它:
$pidOfInterest = $PID # use the PowerShell session's own as an example
(Get-Process -Id $pidOfInterest).CommandLine
笔记:
与 Windows 不同,在 Unix 平台上报告的命令行不是原始命令行的忠实表示;值得注意的是,最初由单引号或双引号强制执行的参数边界会丢失:
注意:在类 Unix 平台上,进程不会收到它们自己必须解析的命令行(不幸的是,在 Windows 上就是这种情况);相反,它们会收到一系列逐字逐句的参数。因此,没有这样的原始命令行,只有特定于 shell 的命令行被传递给原始shell,然后将其转换为在创建时传递给进程的逐字参数数组。
在 macOS 上,ps
下面详述的基于 - 的解决方案不提供有关原始参数边界的信息,只是将逐字参数与空格连接起来,因此通常不能期望生成的命令行字符串像原始调用一样工作。
在 Linux 上,特殊/proc/<pid>/cmdline
文件确实保留了原始参数边界,只需使用NUL
字符 ( 0x0
) 而不是空格来连接逐字参数;但是,要从中重建一个工作命令行需要付出巨大的努力(特别是需要根据需要重新创建引用和转义),甚至这也提出了一个概念上的挑战:考虑到 PowerShell的例如,语法与 Bash 的不同?因此,上面的命令在 Linux 上也只是简单地将逐字参数与空格连接起来,这与ps
在 macOS 上的方式相同。
访问该.CommandLine
属性在性能方面的成本很高,因为它在 Windows 上调用 CIM/WMI 调用,并在 Unix 上的子进程中运行外部可执行文件。
在 macOS 上,您可以ps
按如下方式使用标准实用程序[1] ,但请注意,它返回的命令行缺少原始引用:
# 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
注意:command
是字段名称的非标准变体,args
不受后者 64 个字符的限制,Linux 和 macOS 都支持。
为了说明引用问题:
以下命令(从 PowerShell 执行):
pwsh -noprofile -noexit -c "'hi there'; ps -o command= `$PID"
输出一个字符串,例如:
/usr/local/bin/pwsh -noprofile -noexit -c 'hi there'; ps -o command= $PID
请注意"..."
包含原始-c
参数的引用是如何丢失的。
[1]优越的Linux 特定替代方案是Get-Content -LiteralPath /proc/$PID/cmdline
,它具有将参数与NUL
字符分开以保留原始参数边界的优点 - 但要查看这些边界需要额外的工作。该ps
解决方案至少也适用于某些 Linux 发行版,但可以想象,有一些正在ps
使用的实现不支持该command
领域。无论哪种方式,ps
解决方案都缺少有关原始参数边界的信息。