解釋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。

更新於:2020年6月6日

8K+ 次瀏覽

啟動你的職業生涯

透過完成課程獲得認證

開始學習
廣告