.net - Start-Process/System.Diagnostics.Process ExitCode 是 $null with -NoNewWindow

标签 .net powershell start-process

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

最佳答案

来自 linked question 的回答的回答/评论:

had to do was cache the process handle. As soon as I did that, $process.ExitCode worked correctly. If I didn't cache the process handle, $process.ExitCode was null.

事实上,对于不会立即终止的进程(与示例中的 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 中添加了解释:

This is a quirk of the implementation of the .NET Process object. The implementation of the ExitCode property first checks if the process has exited. 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. PowerShell intercepts that exception and returns null.

Accessing the Handle property causes the process object to retrieve the process handle and store it internally. Once the handle is stored in the process object, the ExitCode property works as expected.

Start-Process无法启动暂停的进程,并且只有在进程运行时才能获取句柄(看起来),对于短时间运行的进程来说使用起来有点脆弱。

关于.net - Start-Process/System.Diagnostics.Process ExitCode 是 $null with -NoNewWindow,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44057728/

相关文章:

c# - 将环境数据添加到线程

c# - webrequest 和 httpwebrequest 有什么区别

c# - Task.Factory.StartNew() 生成对象未初始化错误

powershell - 如何从字符串中选择一个字符串并在powershell中替换它?

mysql - 错误 0x80131047 加载 MySQL 连接器 DLL

powershell - 忽略特定行的 powershell 脚本失败

c#:在 my.settings 中存储大量数据

powershell - 通过 Powershell 创建 Azure 流分析作业

windows - 如何从提升的 PowerShell 控制台以非管理员身份运行进程?

powershell - 在 Start-Process 中添加一个命令以向 Plink 提供 "y"输入