【问题标题】:Start-Process / System.Diagnostics.Process ExitCode is $null with -NoNewWindowStart-Process / System.Diagnostics.Process ExitCode 是 $null 和 -NoNewWindow
【发布时间】:2018-10-29 16:35:42
【问题描述】:

Powershell cmdlet Start-Process 行为异常:

当我启动另一个控制台进程并指定-NoNewWindow 时,ExitCode 属性(int!)为空。

这是一个测试:除了cmd 之外的其他东西也是如此。本次测试是在 Win10 和 PS5 上进行的,Win7 和 PS5 也一样:

PS C:\Users\Martin> cmd.exe /Cver

Microsoft Windows [Version 10.0.15063]
PS C:\Users\Martin> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.15063.296
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.15063.296
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


PS C:\Users\Martin> $pNewWindow = Start-Process -FilePath "cmd.exe" -ArgumentList '/C"exit 42"' -PassThru
PS C:\Users\Martin> $pNewWindow.WaitForExit()
PS C:\Users\Martin> $pNoNewWindow.HasExited
True
PS C:\Users\Martin> $pNewWindow.ExitCode
42
PS C:\Users\Martin> $pNoNewWindow = Start-Process -FilePath "cmd.exe" -ArgumentList '/C"exit 42"' -PassThru -NoNewWindow

PS C:\Users\Martin> $pNoNewWindow.WaitForExit()
PS C:\Users\Martin> $pNoNewWindow.HasExited
True
PS C:\Users\Martin> $pNoNewWindow.ExitCode
PS C:\Users\Martin> $pNoNewWindow.ExitCode -eq $null
True
PS C:\Users\Martin> $pNoNewWindow | Get-Member | ? {$_.Name -imatch "exit"}


   TypeName: System.Diagnostics.Process

Name        MemberType Definition
----        ---------- ----------
Exited      Event      System.EventHandler Exited(System.Object, System.EventArgs)
WaitForExit Method     bool WaitForExit(int milliseconds), void WaitForExit()
ExitCode    Property   int ExitCode {get;}
ExitTime    Property   datetime ExitTime {get;}
HasExited   Property   bool HasExited {get;}


PS C:\Users\Martin>

...所以,属性在那里,但它是null,即使它是int

【问题讨论】:

标签: .net powershell start-process


【解决方案1】:

来自linked question的回答/评论:

必须做的是缓存进程句柄。一旦我这样做了, $process.ExitCode 就可以正常工作。如果我没有缓存进程句柄,$process.ExitCode 为空。

确实,对于立即终止的进程(与示例中的 cmd.exe 不同),解决方法有效:

$proc = Start-Process -NoNewWindow -PassThru ...
$handle = $proc.Handle # cache proc.Handle https://stackoverflow.com/a/23797762/1479211
$proc.WaitForExit()
$proc.ExitCode ... will be set

一位用户在comments添加了解释:

这是 .NET Process 对象实现的一个怪癖。 ExitCode 属性的实现首先检查进程是否已退出。出于某种原因,执行该检查的代码不仅查看 HasExited 属性,还验证过程句柄是否存在于过程对象和throws an exception if it is not 中。 PowerShell 拦截该异常并返回 null。

访问 Handle 属性会导致进程对象检索进程句柄和store it internally。一旦句柄存储在进程对象中,ExitCode 属性就会按预期工作。

由于Start-Process不能启动挂起的进程,而且只有进程在运行(出现)才能获取句柄,所以对于短时间运行的进程使用有点脆。

【讨论】:

    【解决方案2】:

    我们在环境中遇到了类似的问题。 在执行以下命令时:

    Start-Process -FilePath C:\Windows\system32\reg.exe -PassThru -Wait -NoNewWindow
    

    Start-Process -FilePath C:\Windows\system32\reg.exe -PassThru -Wait -WindowStyle Hidden
    

    正如 Martin Ba 所说,在 Start-Process 能够从进程中获取句柄之前,启动的进程 (reg.exe) 似乎已经停止。

    使用-Wait.WaitForExit() 没有区别,因为这两种方法都会检查进程是否已退出。如果它确实退出,PowerShell 将无法获得进程的必要句柄。 Handle 是必需的,因为它包含已启动进程的 ExitCode。

    如果进程已经退出,则会抛出以下错误:

    System.Management.Automation.CmdletInvocationException: Cannot process request because the process (<ProcessIdHere>) has exited. ---> 
    System.InvalidOperationException: Cannot process request because the process (<ProcessIdHere>) has exited.
      at System.Diagnostics.Process.GetProcessHandle(Int32 access, Boolean throwIfExited) 
      at System.Diagnostics.Process.OpenProcessHandle(Int32 access) 
      at System.Diagnostics.Process.get_Handle()
    

    使用-WindowStyle Hidden 代替-NoNewWindow 可以减少错误发生的频率。这是因为 -WindowStyle Hidden 正在创建一个新的 Shell(--> 更多开销),而 -NoNewWindow 使用当前的 Shell。

    我们为此问题创建了一个 UserVoice 条目。也许 PowerShell 团队能够解决此问题:https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/35737357--bug-start-process-might-not-return-handle-exitco

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-13
      • 1970-01-01
      • 1970-01-01
      • 2013-03-14
      相关资源
      最近更新 更多