解釋PowerShell中的Try/Catch/Finally塊
PowerShell中的**Try/Catch**塊用於處理指令碼中產生的錯誤。具體來說,這些錯誤應該是終止性錯誤。PowerShell中的**Finally**塊並非每次都必須與**Try/Catch**一起使用,但無論是否發生錯誤,它都會執行。
因此,當使用**Try**塊時,**Catch**塊是必須的,但**Finally**塊不是必須的。
帶有終止性錯誤的Try/Catch塊 - 下面是無Finally塊的終止性錯誤示例。
示例
try{ This is not allowed "This is Allowed" } catch{ Write-Host "Error occured" -BackgroundColor DarkRed }
輸出
PS C:\WINDOWS\system32> try{ This is not allowed "THis is allowed" } catch{ Write-Host "Error occured" -BackgroundColor Darkred } Error occured
在上面的示例中,我們返回了一些不允許的內容,但下一行是正常的,儘管由於終止性錯誤而無法執行。
我們的目標是捕獲Try塊中生成的異常和錯誤訊息。眾所周知,錯誤儲存在$Error變數中。如果你檢查$error變數的輸出,你可以看到整個檢視,但是每當你執行任何指令碼並處理錯誤時,請確保使用$error.clear()命令清除舊錯誤或使用新的PowerShell控制檯。如果你知道錯誤變數在陣列中的特定位置,可以直接使用它。例如,$error[2]
PS C:\WINDOWS\system32> $Error This : The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. At line:3 char:5 + This is not allowed + ~~~~ + CategoryInfo : ObjectNotFound: (This:String) [], CommandNotFoundException + FullyQualifiedErrorId : CommandNotFoundException
我們可以檢視$Error變數的所有屬性。
PS C:\WINDOWS\system32> $Error | Get-Member | Select Name, MemberType Name MemberType ---- ---------- Equals Method GetHashCode Method GetObjectData Method GetType Method ToString Method CategoryInfo Property ErrorDetails Property Exception Property FullyQualifiedErrorId Property InvocationInfo Property PipelineIterationInfo Property ScriptStackTrace Property TargetObject Property PSMessageDetails ScriptProperty
上面的一些屬性有助於查詢異常和錯誤詳細資訊。讓我們看看它們,我們也可以在Catch塊中利用它們。
首先是InvocationInfo屬性。你也可以使用$Error[0],但這到目前為止是唯一生成的錯誤,所以我們直接使用$Error,但是你不能直接使用$error變數獲得自動建議彈出視窗。
PS C:\WINDOWS\system32> $Error.InvocationInfo MyCommand : BoundParameters : {} UnboundArguments : {} ScriptLineNumber : 3 OffsetInLine : 5 HistoryId : 50 ScriptName : Line : This is not allowed PositionMessage : At line:3 char:5 + This is not allowed + ~~~~ PSScriptRoot : PSCommandPath : InvocationName : This PipelineLength : 0 PipelinePosition : 0 ExpectingInput : False CommandOrigin : Internal DisplayScriptPosition :
你可以從Line和PositionMessage獲取特定資訊,如下所示。
PS C:\WINDOWS\system32> $Error.InvocationInfo.Line This is not allowed PS C:\WINDOWS\system32> $Error.InvocationInfo.PositionMessage At line:3 char:5 + This is not allowed + ~~~~
現在檢查Exception屬性。
PS C:\WINDOWS\system32> $Error.Exception The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
異常訊息
PS C:\WINDOWS\system32>$error.Exception.Message The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
你可以使用你認為有助於顯示錯誤訊息的其他屬性。我們將在Catch塊中使用其中的一些來捕獲錯誤。由於我們正在使用當前錯誤,我們將使用$_.來處理當前的**錯誤/異常**。
$error.clear() try{ This is not allowed "THis is allowed" } catch{ Write-Host "`nError Message: " $_.Exception.Message Write-Host "`nError in Line: " $_.InvocationInfo.Line Write-Host "`nError in Line Number: "$_.InvocationInfo.ScriptLineNumber Write-Host "`nError Item Name: "$_.Exception.ItemName }
輸出
Error Message: The term 'This' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again. Error in Line: This is not allowed Error in Line Number: 3 Error Item Name:
正如我們在上面看到的,沒有Finally塊,Try/Catch仍然可以工作。你可以新增Finally塊來清除你的變數和錯誤,並顯示任何訊息。
try{ This is not allowed "THis is allowed" } catch{ Write-Host "`nError Message: " $_.Exception.Message Write-Host "`nError in Line: " $_.InvocationInfo.Line Write-Host "`nError in Line Number: "$_.InvocationInfo.ScriptLineNumber Write-Host "`nError Item Name: "$_.Exception.ItemName } finally{ "This is going to run anyway" $error.clear() }
帶有非終止性錯誤的Try/Catch塊。
正如我們在上面的示例中看到的,終止性錯誤可以用Try/Catch塊控制,但非終止性錯誤不能,因為它們是內建cmdlet和函式生成的錯誤,並且**Error**操作的預設首選項是Continue,因此即使錯誤未被處理,下一個命令也會繼續執行。
PS C:\WINDOWS\system32> $ErrorActionPreference Continue
要將非終止性錯誤強制轉換為終止性錯誤,我們需要將$ErrorActionPreference變數更改為Stop,或者需要使用ErrorAction引數並將其值設定為Stop。在這裡,我們將使用ErrorAction引數,因為我們只需要它用於特定命令,而不是整個指令碼。
示例
$error.clear() try{ Get-Service WhichService -ErrorAction Stop } catch{ Write-Host "`nError Message: " $_.Exception.Message Write-Host "`nError in Line: " $_.InvocationInfo.Line Write-Host "`nError in Line Number: "$_.InvocationInfo.ScriptLineNumber Write-Host "`nError Item Name: "$_.Exception.ItemName } finally{ "This is going to run anyway" $error.clear() }
輸出
Error Message: Cannot find any service with service name 'WhichService'. Error in Line: Get-Service WhichService -ErrorAction Stop Error in Line Number: 4 Error Item Name: This is going to run anyway
正如你可以在上面的示例中看到的,Get-Service產生非終止性錯誤,我們可以透過–ErrorAction Stop引數將其轉換為終止性錯誤,並且Catch塊已捕獲相同的異常。
手動處理特定異常
如果你想處理特定型別的異常,你可以在catch塊中提供異常名稱。要了解異常的名稱,你需要獲取$Error變數的屬性,它是**GetType()**。在下面的示例中,我們需要從下面的錯誤輸出中找到異常名稱。
示例
PS C:\WINDOWS\system32> Test-Connection Remote-Computer -Count 1 -ErrorAction Stop Test-Connection : Testing connection to computer 'Remote-Computer' failed: No such host is known At line:1 char:4 + Test-Connection Remote-Computer -Count 1 -ErrorAction Stop + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : ResourceUnavailable: (Remote-Computer:String) [Test-Connection], PingException + FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands. TestConnectionCommand
假設你的錯誤儲存在$Error[0]變數中,你需要執行以下命令來獲取要在catch塊中使用的異常名稱。
$Error[0].Exception.GetType().FullName
PS C:\WINDOWS\system32> $Error[0].Exception.GetType().FullName System.Management.Automation.MethodInvocationException
你使用上面的命令獲得了異常型別名稱,你可以在catch塊中使用相同的名稱,這樣catch塊將只捕獲該特定異常。
$error.clear() try{ Test-Connection Remote-Computer -Count 1 -ErrorAction Stop } catch [System.Net.NetworkInformation.PingException]{ Write-Host $_.Exception.Message -BackgroundColor DarkRed }
輸出
PS C:\WINDOWS\system32> $error.clear() try{ Test-Connection Remote-Computer -Count 1 -ErrorAction Stop } catch [System.Net.NetworkInformation.PingException]{ Write-Host $_.Exception.Message -BackgroundColor DarkRed -NoNewline } Testing connection to computer 'Remote-Computer' failed: No such host is known
捕獲多個PowerShell異常。
你也可以在PowerShell中捕獲多個異常。為此,你可以使用一個Try塊和多個catch塊。
示例
$error.clear() $ErrorActionPreference = "Stop" try{ Get-ItemProperty C:\temp\cominfo1.html Test-Connection Remote-Computer -Count 1 } catch [System.Management.Automation.ItemNotFoundException]{ Write-Host $_.Exception.Message -BackgroundColor DarkRed } catch [System.Net.NetworkInformation.PingException]{ Write-Host "" Write-Host $_.Exception.Message -BackgroundColor DarkRed } Finally{ Write-Output "`nSetting up ErrorActionPreference to the Default value" $ErrorActionPreference = "Continue" }
輸出
Cannot find path 'C:\temp\cominfo1.html' because it does not exist. Setting up ErrorActionPreference to the Default value
在這裡,在第一個命令本身就生成了錯誤,因此下一個命令將不會執行。如果第一個命令沒有產生任何錯誤,則將檢查下一個命令,如果發生異常,則將執行具有該特定異常塊的Catch。
如果你不想處理多個異常,並且仍然需要忽略某些命令的錯誤,但這些錯誤不應該透過catch塊,以便下一個命令可以執行,那麼你可以在ErrorAction引數中使用Ignore或SilentlyIgnore。