簡體   English   中英

無論腳本在“常規” PowerShell控制台還是在Powershell ISE中運行,如何以相同的方式處理錯誤?

[英]How to handle errors in a way that works the same whether the script runs in “regular” powershell console or in powershell ISE?

我有這個簡單的腳本:

$ErrorActionPreference = "Stop"
try 
{ 
    cmd /c mklink a .\DataSvc.sln 
} 
catch 
{ 
    "Failed" 
}

(文件DataSvc.sln存在)

當我在ISE powershell控制台中運行它時,它會顯示“失敗”,而當我從“常規” powershell控制台中進行操作時,它會顯示“您沒有足夠的特權執行此操作”。

ISE:

在此處輸入圖片說明

定期:

在此處輸入圖片說明

在兩種情況下,我應該如何編寫它以便打印“失敗”?

編輯1

您必須在Windows 10開發人員模式關閉的情況下以普通帳戶(不是提升帳戶)身份運行它。 如果您不知道什么是Windows 10開發人員模式,則可以(針對此問題)。

不幸的是,不同的主機對外部程序的 stderr輸出進行不同的處理。

  • ISE將stderr輸出路由到PowerShell自己的錯誤流,這解釋了為什么寫入stderr的任何內容都會觸發try / catch處理程序。

    • 在一個側節點上:考慮從過時的ISE切換到帶有PowerShell擴展的 Visual Studio Code 未來的開發工作集中在此,並且行為與控制台沒有什么不同(至少在這方面)。
  • 常規控制台會將stderr輸出修補到控制台 ,在這種情況下,不會觸發任何錯誤。

由於存在錯誤 ,您當前(Windows PowerShell v5.1 / PowerShell Core v6.1)可以通過在PowerShell中重定向流編號2在控制台中觸發錯誤:

$ErrorActionPreference = "Stop"
try {
  cmd /c 'echo tostderr >&2' 2>&1 # even 2>$null would trigger an error(!)
} catch {
  "Failed"
}

但是,我不會依賴它,因為該錯誤可能會(而且希望會)得到修復。

退后一步:正如注釋中的鏈接所隱含的那樣,外部程序是否失敗應該僅從其退出代碼中得出,而不應該從存在stderr輸出中得出,因為許多程序使用stderr輸出來報告錯誤以外的信息 (例如作為診斷信息或僅作為警告)。

因此,僅應使用if ($LASTEXITCODE -ne 0)來確定失敗。


如果由於某種原因您確實需要根據stderr輸出的存在來推斷出失敗-例如,由於某些程序無法正確反映其退出代碼中的失敗-您可以嘗試以下方法,該方法現在和之后都適用上述錯誤已修復:

$ErrorActionPreference = "Stop"
try {
  cmd /c 'echo tostderr >&2' 2>&1 | ForEach-Object {
    if ($_ -is [System.Management.Automation.ErrorRecord]) { Throw $_ }
    $_
  }
} catch {
  "Failed"
}

這依賴於將錯誤流合並到成功流中,然后根據它們的類型來檢測源自stderr的行。

請注意,盡管在PowerShell內部,您可以使用通用參數-ErrorVariable / -ev在一個變量中收集命令的錯誤輸出,但是在調用外部程序時沒有類似的機制。 但是,在此GitHub問題中提出了引入這種機制的建議。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM