启动过程不适用于启动睡眠

我的目标是运行多个进程,并保存它们的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]结束,但结果还是一样。

问题:为什么我在calc下没有Processname?如果删除Start-Sleep 1,则在calc下得到Processname。这是为什么?这是启动应用程序的正确方法,还是我做错了什么?我的操作系统:Windows 10 Home

oopsqoo 回答:启动过程不适用于启动睡眠

您的问题与Start-Sleep的使用无关。

相反,问题在于,从Windows 10开始, calc.exe只是最终启动的进程的 stub 可执行文件,并且存根进程会立即退出。因为它已经启动了真正的可执行文件

如果您删除了Start-SleepStart-Process之间的echo调用,则$startedProcesses中包含的 stub 过程对象通常会反映当时calc.exe列中存根可执行文件的名称-ProcessName-由于仍在运行中(虽然只是很快),但是您仍然无法跟踪 real 可执行文件的进程生存期,并通过该对象退出代码。

实际可执行文件的名称为Calculator.exe,其确切路径包含完整的AppX软件包名称(软件包名称,版本号和发布者ID):

例如,启动calc.exe后,(Get-Process Calculator).Path会产生类似以下内容:

C:\Program Files\WindowsApps\Microsoft.WindowsCalculator_10.1908.0.0_x64__8wekyb3d8bbwe\Calculator.exe

但是,即使您知道该路径,也无法使用它直接启动计算器

Calculator,作为 AppX软件包(通常通过Microsoft Store分发的UWP应用程序),貌似必须通过其URL协议方案发布 [1 ]

Start-Process ms-calculator:

不幸的是,从PowerShell Core 7.0.0-preview.5 / Windows PowerShell v5.1开始,-PassThru添加到具有Start-Process的AppX软件包URL的调用中会导致 error ,而不是返回代表已启动进程的对象-尽管Calculator仍会启动:

# 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.
...

该问题已在this GitHub issue中报告。


解决方法

# 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 most recently launched instance is used.
$processStatus = (Get-Process -Name Calculator | Sort-Object TotalProcessTime)[0]

注意:此方法并非万无一失,因为假设另一个进程可以假设同时启动一个Calculator实例,但在实践中应该足够健壮。


[1]有关通过包名称或其中基于通配符的部分(例如*Calculator*,请参见this answer)自动发现AppX应用的协议名称的方法。

本文链接:https://www.f2er.com/3155617.html

大家都在问