錯誤處理
到目前為止,您已瞭解如何新增參數和流量控制建構,讓您的指令碼有彈性且能更安全地使用。 但有時候您會在指令碼中收到錯誤。 您需要有方式來處理這些錯誤。
需要考慮的因素有兩項:
如何處理錯誤。 有時候您會收到可以復原的錯誤,有時候最好是停止指令碼。 請務必考慮可能發生的錯誤類型,以及如何妥善管理。
錯誤有多嚴重。 有各種不同類型的錯誤訊息。 有些是使用者覺得不正常的警告。 有些則是更嚴重的,且使用者真的需要注意。 您的錯誤處理方法取決於錯誤的類型。 這種方法可能是來自呈現訊息來提高嚴重性層級,並可能會停止指令碼的任何事項。
錯誤
例如,Cmdlet 或函式可能會產生許多類型的錯誤。 我們建議您撰寫程式碼來管理每個可能發生的錯誤類型,並在指定類型時適當地進行管理。 例如,假設您正在嘗試寫入檔案。 根據錯誤的不同,您可能會遇到各種類型的錯誤。 如果您不允許寫入檔案,您可能會收到一種類型的錯誤。 如果檔案不存在,您可能會收到另一種類型的錯誤,依此類推。
當您執行 PowerShell 時,可以取得兩種類型的錯誤:
終止錯誤。 此類型的錯誤將會在發生錯誤的資料列上停止執行。 您可使用
Try-Catch或Trap來處理這類型的錯誤。 如果未處理錯誤,指令碼將會在該點結束,且不會執行任何陳述式。注意
Trap建構在此課程模組範圍之外。 如果您有興趣,請參閱 關於陷阱。非終止錯誤。 這種類型的錯誤會通知使用者發生問題,但指令碼會繼續。 您可以將此類型的錯誤升級為終止錯誤。
使用 Try/Catch/Finally 管理錯誤
您可以將終止錯誤視為未預期的錯誤。 這些錯誤很嚴重。 當您處理其中一種情況時,您應該考慮是何種類型的錯誤,以及該怎麼處理。
有三個相關的建構可協助您管理這類型的錯誤:
Try。 您會使用Try區塊來封裝一或多個陳述式。 您會將想要執行的程式碼 (例如,寫入資料來源的程式碼) 放在大括弧內。Try至少必須有一個Catch或Finally區塊。 其外觀如下:Try { # Statement. For example, call a command. # Another statement. For example, assign a variable. }Catch。 當發生錯誤時,您會使用此關鍵字來「攔截」或「管理」錯誤。 然後,您會檢查例外狀況物件,以瞭解發生了哪種類型的錯誤、發生的位置,以及指令碼是否可以復原。Catch緊接在Try之後。 如果您想要的話,可以包含一個以上的Catch(每種類型的錯誤各一個)。 以下為範例:Try { # Do something with a file. } Catch [System.IO.IOException] { Write-Host "Something went wrong" } Catch { # Catch all. It's not an IOException but something else. }指令碼會嘗試執行執行一些 I/O 工作的命令。 第一個會
Catch攔截特定類型的錯誤:[System.IO.IOException]。 最後一個Catch會攔截任何不是[System.IO.IOException]的錯誤。Finally。 不論是否發生任何錯誤,都會執行此區塊中的陳述式。 您可能不會使用這種區塊,但這對清除資源很有用。 若要使用,請將其新增為最後一個區塊:Try { # Do something with a file. } Catch [System.IO.IOException] { Write-Host "Something went wrong" } Catch { # Catch all. It's not an IOException but something else. } Finally { # Clean up resources. }
檢查錯誤
我們已在攔截錯誤的內容中討論過例外狀況物件。 您可使用這些物件來檢查發生錯誤的原因,並採取適當的措施。 例外狀況物件包含:
訊息。 此訊息會簡短告訴您發生錯誤的地方。
堆疊追蹤。 堆疊追蹤會告知您在錯誤之前執行的陳述式。 假設您呼叫了函式 A、後面接著 B,然後是 C。指令碼會停止回應 C。堆疊追蹤將會顯示該呼叫鏈。
違規的資料列。 例外狀況物件也會告訴您當錯誤發生時,指令碼正在執行的資料列。 此資訊可協助您偵錯您的程式碼。
那麼,您要如何檢查例外狀況物件呢? 有一個具有 exception 屬性的內建變數 $_。 例如,若要取得錯誤訊息,請使用 $_.exception.message。 在程式碼中,可能如下所示:
Try {
# Do something with a file.
} Catch [System.IO.IOException] {
Write-Host "Something IO went wrong: $($_.exception.message)"
} Catch {
Write-Host "Something else went wrong: $($_.exception.message)"
}
引發錯誤
在某些情況下,建議您產生錯誤:
非終止錯誤。 例如,針對此類型的錯誤,PowerShell 只會使用
Write-ErrorCmdlet 通知您發生錯誤。 指令碼繼續執行。 這可能不是您想要的行為。 若要提高錯誤的嚴重性,您可以使用像這樣的參數-ErrorAction來引發可攔截的錯誤Try/Catch,如下所示:Try { Get-Content './file.txt' -ErrorAction Stop } Catch { Write-Error "File can't be found" }使用
-ErrorAction參數和值Stop,您可能會造成Try/Catch可能攔截到的錯誤。商務規則。 可能會有一種情況,那就是程式碼不會實際停止回應,但您會基於商務原因而希望如此。 假設您正在處理輸入,並檢查參數是否為路徑。 商務需求可能是只允許特定的路徑,或路徑需要以某種方式來查看。 如果檢查失敗,則會「擲回」錯誤。 在這種情況下,您可以使用
Throw區塊:Try { If ($Path -eq './forbidden') { Throw "Path not allowed" } # Carry on. } Catch { Write-Error "$($_.exception.message)" # Path not allowed. }注意
一般情況下,請不要使用
Throw進行參數驗證。 請改用 驗證屬性 。 如果您無法讓程式碼使用這些屬性,Throw可能 OK。