powershell - Start-Process 与 Start-Sleep 不能很好地配合

标签 powershell

我的目标是运行多个进程并保存它们的 ProcessNameId供以后使用。这是我的代码

[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]但我最终得到了相同的结果。

问题:为什么我没有 calcProcessName ?如果我删除 Start-Sleep 1然后我得到calcProcessName 。这是为什么?这是启动应用程序的正确方法还是我做错了什么?我的操作系统: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/

相关文章:

Azure powershell : find which principal created or modified a given principal

powershell - 非终止错误处理-if $ Error.count和$ ErrorActionPreference = 'stop'之间的区别

batch-file - 设置服务器列表的PW永不过期

powershell - 让 Powershell 处理来自 C# 程序的对象列表

powershell - Powershell中私有(private)函数的缩进输出

powershell - 无法在 Powershell 中使用带有管道变量的 -filter 子句运行 Get-CASMailbox

azure - PowerShell 脚本用于在 azure 容器注册表上保留最新 10 个镜像,其余的需要删除

regex - 正则表达式只删除特定嵌套级别的方括号中的文本?

powershell - 在 Windows Powershell 中获取小时和分钟

c# - Azure Keyvault - "Operation "列表“保管库策略不允许”,但已检查所有权限