简体   繁体   English

Start-Process / System.Diagnostics.Process ExitCode为$ null,带有-NoNewWindow

[英]Start-Process / System.Diagnostics.Process ExitCode is $null with -NoNewWindow

The Powershell cmdlet Start-Process is acting weirdly: Powershell cmdlet Start-Process异常:

When I launch another console process and I specify -NoNewWindow , the ExitCode property (an int !) is null. 当我启动另一个控制台进程并指定-NoNewWindow ,ExitCode属性(一个int !)为null。

Here's a test: Same with something else besides cmd . 这是一个测试:与cmd之外的其他东西相同。 This test was on a Win10 with PS5, it is also the same with Win7 and PS5: 该测试是在带有PS5的Win10上进行的,与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>

... So, the Property is there, but it's null , even though it's an int ? ...因此,该属性在那里,但是它是null ,即使它是一个int吗?

Answer from linked question 's answer's / comment: 链接问题的答案/评论中的答案:

had to do was cache the process handle. 要做的是缓存进程句柄。 As soon as I did that, $process.ExitCode worked correctly. 我这样做后,$ process.ExitCode便可以正常工作。 If I didn't cache the process handle, $process.ExitCode was null. 如果我没有缓存进程句柄,则$ process.ExitCode为null。

and indeed, for a process that doesn't immediately terminate (unlike the cmd.exe in the example), the workaround works: 实际上,对于不会 立即终止的进程(与示例中的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

A user added an explanation in the comments : 用户在评论中添加了解释:

This is a quirk of the implementation of the .NET Process object. 这是.NET Process对象的实现的怪癖。 The implementation of the ExitCode property first checks if the process has exited. ExitCode属性的实现首先检查该进程是否已经退出。 For some reason, the code that performs that check not only looks at the HasExited property but also verifies that the proces handle is present in the proces object and throws an exception if it is not . 出于某种原因,执行该检查的代码不仅查看HasExited属性,还验证proces对象中是否存在proces句柄, 如果不存在, 则会引发异常 PowerShell intercepts that exception and returns null. PowerShell拦截该异常并返回null。

Accessing the Handle property causes the process object to retrieve the process handle and store it internally . 访问Handle属性会使流程对象检索流程句柄并将其存储在内部 Once the handle is stored in the process object, the ExitCode property works as expected. 将句柄存储在流程对象中后,ExitCode属性将按预期工作。

Since Start-Process cannot launch a process suspended, and the handle can only be obtained as long as the process is running (it appears), the usage is a bit brittle for short-running processes. 由于Start-Process无法启动挂起的进程,并且仅在进程正在运行时才可以获取该句柄(出现该句柄),因此对于短时间运行的进程而言,用法有些脆弱。

We encountered a similar issue in our Environment. 我们在环境中遇到了类似的问题。 While executing the following command: 在执行以下命令时:

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

or 要么

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

As stated by Martin Ba, it seems like the started Process (reg.exe) has stopped before Start-Process was able to get a Handle from the Process. 如Martin Ba所述,似乎启动进程(reg.exe)在启动进程能够从进程获取句柄之前已经停止。

Using -Wait or .WaitForExit() does not make a difference because both Methods check if the process has exited. 使用-Wait.WaitForExit()没有区别,因为这两种方法检查进程已退出。 If it did Exit, PowerShell won't be able to get the necessary handle for the Process. 如果退出,PowerShell将无法获取该流程的必要句柄。 The Handle is necessary because it holds the ExitCode of the started Process. 该句柄是必需的,因为它保存了已启动进程的ExitCode。

The following error is thrown, if the Process has already exited: 如果进程已经退出,则会引发以下错误:

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()

Using -WindowStyle Hidden instead of -NoNewWindow may reduce how often the error occurs. 使用-WindowStyle Hidden而不是-NoNewWindow可以减少发生错误的频率。 This is because -WindowStyle Hidden is creating a new Shell (--> more Overhead), whereas -NoNewWindow uses the current Shell. 这是因为-WindowStyle Hidden正在创建新的Shell(->更多开销),而-NoNewWindow使用当前的Shell。

We created a UserVoice entry for this issue. 我们为此问题创建了一个UserVoice条目。 Maybe the PowerShell Team is able to work around this behavior: https://windowsserver.uservoice.com/forums/301869-powershell/suggestions/35737357--bug-start-process-might-not-return-handle-exitco 也许PowerShell团队能够解决此问题: https : //windowsserver.uservoice.com/forums/301869-powershell/suggestions/35737357--bug-start-process-might-not-return-handle-exitco

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM