即使为 type-casting 提供 [Int32],Powershell 也不会将 Foreach-Object 参数从字符串转换为整数

Powershell not converting Foreach-Object parameter from string to integer even when provided [Int32] for type-casting

如问题标题中所述,我有一个 Powershell one-liner 用于按名称杀死 Application/Process 及其所有相关的 children 进程:

powershell -c "Get-Process -Name `"Chrome`" | Select-Object -Property Id | ForEach-Object -Process { Stop-Process -Id $_.Id -Force }"

当我通过删除进程终止代码并仅打印进程 ID 进行测试时,效果如下:

powershell -c "Get-Process -Name `"Chrome`" | Select-Object -Property Id"

这会将属于 Chrome 个实例的所有 ID 显示为:

372
1232
1776
1884
2024
2676
3008
3240

但是当我试图用这个 post 中的第一个代码块杀死那些进程时,它会抛出这个错误:

Stop-Process : Cannot bind parameter 'Id'. Cannot convert value ".Id" to type "System.Int32". Error: "Input string was not in a correct format."

所以我确实为 type-conversion 应用了 [Int32],认为这足以将 ID 以有效格式带入 Stop-Process 部分并杀死它,但这也没有工作:

powershell -c "Get-Process -Name `"Chrome`" | Select-Object -Property Id | ForEach-Object -Process { Stop-Process -Id [Int32]($_.Id) -Force }"

这会引发错误:

The term '.Id' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if
a path was included, verify that the path is correct and try again.
At line:1 char:108
+ ... y Id | ForEach-Object -Process { Stop-Process -Id [Int32](.Id) -Force ...
+                                                               ~~~
    + CategoryInfo          : ObjectNotFound: (.Id:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

任何人都可以帮助解决这个问题并通过不过度延长 one-liner 来使 one-liner 正常工作吗??

立即修复:$_.Id -> `$_.Id

也就是说,您需要防止 up-frontexpandable (double-quoted) string ("...") 中扩展 $_ 传递给新的子进程,通过将 $ 字符转义为 `$ 以便按字面保留它 - 就像你对嵌入的 " 字符所做的那样(`" - 尽管请注意你没有完全需要引用 Chrome 参数)。

或者,鉴于您的字符串实际上不需要在调用方进行插值,您可以简单地使用 verbatim (single-quoted) string ('...'),这也避免了转义嵌入的 $" 个字符。:

powershell -c 'Get-Process -Name "Chrome" | Select-Object -Property Id | ForEach-Object -Process { Stop-Process -Id $_.Id -Force }'

退一步:

如果你真的需要调用另一个 PowerShell 实例 - 作为一个昂贵的子进程 - 从 PowerShell,你可以 使用脚本块,这使得转义问题消失,也可能returns - 反序列化 - 对象而不仅仅是 string 输出:

powershell -c { Get-Process -Name "Chrome" | Select-Object -Property Id | ForEach-Object -Process { Stop-Process -Id $_.Id -Force }

注意:如果您需要合并来自 调用方 作用域的值,您需要通过 [=25= 将它们传递给子进程] 范围;一个简化的例子:powershell -c { Write-Output "$args!" } -Args hi


至于缩短命令本身:

powershell -c { Get-Process Chrome | Stop-Process -Force }

上面利用了-Name隐含作为第一个位置传递参数的目标参数,以及Stop-Process直接操作的能力在 process-info 通过管道接收的对象上,作为 Get-Process.

的输出