我的目标是运行多个进程并保存它们的 ProcessName
和Id
供以后使用。这是我的代码
[System.Collections.ArrayList]$startedProcesses = @()
$processStatus = Start-Process -FilePath notepad.exe -passthru
Start-Sleep 1
$startedProcesses.add($processStatus)
$processStatus = Start-Process -FilePath calc.exe -passthru
Start-Sleep 1
$startedProcesses.add($processStatus)
echo $startedProcesses
该脚本的输出是:
PS C:\Users\wakatana\Desktop\> .\so_question0.ps1
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
235 15 3408 14112 0.08 24812 2 notepad
0 0 0 0.13 21460
我也尝试过替换 [System.Collections.ArrayList]$startedProcesses = @()
与 $startedProcesses = New-Object System.Collections.Generic.List[System.ComponentModel.Component]
但我最终得到了相同的结果。
问题:为什么我没有 calc
下ProcessName
?如果我删除 Start-Sleep 1
然后我得到calc
下ProcessName
。这是为什么?这是启动应用程序的正确方法还是我做错了什么?我的操作系统:Windows 10 家庭版
最佳答案
您的问题与 Start-Sleep
的使用无关.
相反,问题是,从 Windows 10 开始, calc.exe
只是最终启动的进程的 stub 可执行文件, stub 进程在启动真正的可执行文件后立即退出。
如果删除 Start-Sleep
Start-Process
之间的通话和 echo
调用,$startedProcesses
中包含的 stub 进程对象通常确实反射(reflect)了 stub 可执行文件的名称 - calc.exe
- 在 ProcessName
当时的列,由于仍然存在(尽管只是很短的时间),但您仍然无法通过该对象跟踪真实可执行文件的进程生命周期和退出代码。
真正的可执行文件的名称是 Calculator.exe
,其确切路径包含完整的 AppX 包名称(包名称、版本号和发布者 ID):
例如,启动 calc.exe
后, (Get-Process Calculator).Path
产生类似:
C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1908.0.0_x64__8wekyb3d8bbwe\Calculator.exe
但是,您不能使用该路径直接启动计算器 - 您将得到 Access denied
错误,即使在海拔高度下运行时也是如此。
计算器作为一个 AppX 包(通常通过 Microsoft Store 分发的 UWP 应用程序),最容易通过其 URL 方案启动:
Start-Process ms-calculator:
注意:
通过包名称或其基于通配符的部分自动发现 AppX 应用程序的 URL 方案名称 - 例如
*Calculator*
- 参见this answer .不太方便的替代方法是使用
shell:
基于应用程序 AppID 的 URL - 请参阅 this answer .
不幸的是,从 PowerShell (Core) 7.2/Windows PowerShell v5.1 开始,添加 -PassThru
使用 Start-Process
调用 AppX 包 URL导致错误,而不是返回表示已启动进程的对象 - 尽管计算器仍然启动; 同样适用于-Wait
:
# Launches Calculator, but doesn't return a process object
# and reports an error instead:
PS> Start-Process ms-calculator: -PassThru
Start-Process : This command cannot be run completely because the system cannot find all the information required.
...
该问题已在 GitHub issue #10996 中报告.
解决方法:
# Invoke the *stub executable* synchronously, so that
# the real executable has already been launched by the time
# the call returns.
Start-Process -Wait -FilePath calc.exe
# Now get the real process object, named 'Calculator'.
# The newly launched or a preexisting instance is used (see below).
$processStatus = Get-Process -Name Calculator |
Where-Object SessionId -eq (Get-Process -ID $PID).SessionId).ID
注意:计算器只会为每个用户 session (窗口站)创建一个进程:如果进程已存在,则后续启动将委托(delegate)给该进程。
关于powershell - Start-Process 与 Start-Sleep 不能很好地配合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58721461/