说明PowerShell中的Try / Catch / Finally块

PowerShell中的Try / Catch块用于处理脚本中产生的错误。具体而言,错误应该是终止错误。在最后在PowerShell中块不是强制性的,每次沿写try / catch语句,但它会不管发生错误或不执行。

因此,当您使用Try块时,Catch块是必需的,但不是Final块。

  • 尝试/捕获具有终止错误的块-以下是没有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变量获取AutoSuggestion Popup。

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
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:

正如我们在上面看到的,没有Final块,但是Try / Catch继续起作用。您可以添加Final模块来清除变量和错误并显示任何消息。

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块控制终止错误,但不能终止错误,因为它们是内置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 Block捕获了相同的异常。

  • 手动处理特定异常

如果要处理特定类型的异常,则可以在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。