解释 PowerShell 中的 Try/Catch/Finally 块

powershellmicrosoft technologiessoftware & coding更新于 2026/1/6 2:37:17

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 变量的具体位置,则可以直接使用它。例如,$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
+    ~~~~

现在检查异常属性。

PS C:\WINDOWS\system32> $Error.Exception
"This"一词无法识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包含路径,请验证路径是否正确,然后重试。

异常消息

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 操作的默认首选项是"继续",因此即使错误未得到处理,下一个命令也会继续运行。

PS C:\WINDOWS\system32> $ErrorActionPreference
Continue

要将非终止错误强制转换为终止错误,我们需要将 $ErrorActionPreference 变量更改为"停止",或者使用带有"停止"值的 ErrorAction 参数。这里我们将使用 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 选项。


相关文章