解释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+ 次浏览

启动你的职业生涯

通过完成课程获得认证

开始学习
广告
© . All rights reserved.