问题描述
在PowerShell中,使用Get-WmiObject win32_process
可以获取Windows(like this)中任何活动进程的命令行参数。在Linux和/或OSX中您如何做?
可以肯定,ps
命令可以做到这一点,但是我正在寻找PowerShell本地解决方案,以便能够保持强类型。
解决方法
注意:从PowerShell Core 7.1.0-rc.2开始,存在一个新的7.1 .CommandLine
ETS脚本属性,该属性确定Windows上的命令行和Linux上的 。
但是:
- 在撰写本文时,GitHub feature request #13943尚未提供针对 macOS 的解决方案。
- Linux {em> 解决方案的行为有些出乎意料,如GitHub issue #13944 中所述-以下解决方案可以解决此问题,尽管以失去参数边界为代价。
底部详细介绍的解决方案可在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上是这样);相反,他们收到了 verbatim 参数的 array 。因此,没有这样的原始命令行,只有传递给原始 shell 的特定于Shell的命令行,然后将其转换为在创建时传递给进程的逐字参数数组。
-
在macOS上,下面详细介绍的基于
ps
的解决方案提供有关原始参数边界的 no 信息,并仅将逐字参数与空格连接在一起,因此生成的命令行通常不能期望字符串像原始调用一样工作。 -
在Linux上,特殊的
/proc/<pid>/cmdline
文件 do 仅使用NUL
个字符(0x0
)而不是空格来保留原始参数边界。加入逐字辩论;但是,要从中重建一个有效的命令行将需要不懈的努力(特别是需要根据需要重新创建引号和转义符),甚至提出了一个概念上的挑战:您使用什么shell 命令行,例如,假设PowerShell的语法不同于Bash的语法?因此,上面的命令还将Linux上的逐字参数简单地与空格连接起来,就像ps
在macOS上一样。
-
-
访问
.CommandLine
属性在性能上是昂贵的,因为它在Windows上调用CIM / WMI调用,并在Unix的子进程中运行外部可执行文件。
在macOS上,您可以按以下方式使用标准ps
utility [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
解决方案都缺少有关原始参数边界的信息。