要了解為什麼Start-Process和其他所有命令都有限制,首先必須了解典型EXE文件的工作原理。當運行EXE文件時,它會執行其設計用於的任何操作;例如,發送ping命令(ping)、啟動軟件安裝程序(setup)、查找某些DNS記錄(nslookup)等等。對於part和Start-Process a
nd和其他命令來啟動進程,這非常有效。這很簡單。當EXE返回某些輸出時,就出現了限制。
我們可以以多種不同的方式在PowerShell 中啟動進程。我們有PowerShell的Start-Process和Invoke-Expression
命令,可以直接調用可執行文件,或使用&符號(&
)來調用表達式。最常見的方法是使用Start-Process
,因為這可能是最直觀的方法。PowerShell以其直觀的命令命名方法而聞名,而Start-Process是一個很好的選擇。然而,該命令有限制。
流
類似於其他可執行文件(不僅限於Windows)的EXE文件具有標準流(standard streams)的概念。標準流是可執行文件返回輸出的方式。這些流有三種類型:stdin、stdout和stderr。stdin是傳遞給可執行文件的流,我們在這裡不會關注它。stdout是可執行文件用於發送正常非錯誤輸出的流。
以PowerShell術語來說,stdout可以視為Write-Output
返回的內容。當發生錯誤時(取決於可執行文件的開發人員是否正確編寫),可執行文件應該通過stderr返回輸出。這是一個專門用於返回任何錯誤信息的流。
這些流使得這些可執行文件的用戶能夠區分什麼是典型的輸出和什麼是錯誤。流已經存在了數十年,因此Windows和PowerShell都非常了解它們並且採用了自己的方式。
退出代碼
退出代碼、返回代碼或結果代碼是可執行文件遵循的另一個古老概念。退出代碼是一個整數,允許可執行文件在退出時向用戶發出狀態信號。
一些標準的退出代碼程序應該遵循,例如退出代碼為0表示一切正常,退出代碼3010表示需要重新啟動等等。PowerShell可以以幾種不同的方式捕獲這個退出代碼,例如使用$LastExitCode
這個自動變量。退出代碼是可執行文件向用戶傳遞信息的另一種方法。
捕獲流和退出代碼
現在您已經了解我們要處理的內容,讓我們舉個例子。為了保持簡單,我們使用經典的ping.exe。首先,我會ping google.com,這將返回一個成功的結果。在這裡,我們不使用PowerShell start process。
I’ll now purposefully ping a host that doesn’t resolve a DNS name and will fail. Notice the value of $LastExitCode
.
你看到退出代码不同是因为ping的结果不同,但你没有看到流,因为原生的PowerShell对可执行文件的区别不太理解。你在控制台看到的文本是白色的;不是你熟悉和喜欢的红色错误文本。
我们可以以几种不同的方式捕获流并重定向到文件,比如使用>
和2>
,就像下面这样。这是老派的方式。
请注意,即使ping.exe返回退出代码1(如上所示),输出仍然会传递到标准输出。这是很常见的。返回的流和退出代码完全取决于开发人员,并且有很多不同的风格,不幸的是。
如果你想采用“新派”的方式,你可以使用Start-Process
并使用-RedirectStandardError
和-RedirectStandardOutput
参数,但它们仍然只会被重定向到文件。
Start-Process的限制
你可以看到,启动进程并返回一些常见的输出并不常见。此外,PowerShell对流和退出代码的处理不太好。如果我想使用Start-Process运行ping.exe
并想要跟踪结果中发生的情况,我每次都必须像这样做每次我想运行一个可执行文件。
I still wouldn’t get my error text either!
让我们修复所有这些问题。从PowerShell Gallery下载一个我创建的名为Invoke-Process
的小函数。
现在使用一个有效的主机运行ping并看看会发生什么。

請注意我們得到了相同的輸出。這很好!
現在運行使用無效主機的 ping。

現在請注意,如果出現問題,我們會得到典型的紅色錯誤文本。 Invoke-Process
在內部使用 Start-Process
來捕獲 stdout、stderr 和退出代碼,然後將輸出發送到應該去的流。這樣做是應該的!
太糟糕了,PowerShell 沒有讓從可執行文件工作的流和退出代碼變得更容易,但我想現在已經是開源的,我們可以加進去了!