当前位置:网站首页 > 更多 > 玩电脑 > 正文

[玩转系统] 如何在 PowerShell 中使用 Try、Catch、Finally

作者:精品下载站 日期:2024-12-14 03:40:31 浏览:15 分类:玩电脑

如何在 PowerShell 中使用 Try、Catch、Finally


PowerShell 脚本中的错误可能会停止脚本的执行,但有时这是完全没有必要的。 尝试 PowerShell 中的 Catch 块帮助您正确处理这些错误。

以下面的例子为例;您需要更新 20 名员工的职务。人力资源部门给了你一份名单,上面有姓名和新职位,但他们拼错了其中一个名字。

如果没有 PowerShell Try Catch 块,您的脚本将在中间的某个位置停止,从而导致更新了一半的记录。您现在需要弄清楚脚本在哪里停止以及哪个用户触发了错误。

通过 PowerShell 中的 Try Catch,我们可以处理整个列表,并在出现问题时编写正确的错误消息(甚至发送电子邮件)。

在本文中,我们将了解如何在 PowerShell 中使用 Try、Catch、Finally 以及如何找到要捕获的正确错误消息。

Powershell 最后尝试捕获

我们首先看一下 Try Catch Final 块的基础知识。 Powershell 中的 Try Catch 块始终包含一个 Try 块和至少一个 Catch 块。 Finally 块是可选的,无论 Try 块的结果如何,该块中的代码都将始终运行。

try
{
    # Try something that could cause an error
    1/0
}
catch
{
    # Catch any error
    Write-Host "An error occurred"
}
finally
{
    # [Optional] Run this part always
    Write-Host "cleaning up ..."
}

在 Try 块中,放置可能导致错误的脚本。保持这部分很小,并且不要在其中组合太多功能。 PowerShell Try Catch 块的目标是实现正确的错误处理,并且只有在一次尝试一个棘手的函数时才能做到这一点。

如果我们采用以下(简化的)示例来更新职位名称:

try{
	# Find the user to update
	$ADUser = Get-AzureAdUser -SearchString $user.name

	# Update the job title
	Set-AzureAdUser -ObjectId $ADUser.ObjectId -JobTitle $user.jobtitle

	# Send an email that the job title is updated
	Send-MailMessage -SmtpServer $smtp.address -To $user.mail -From $smtp.from -Subject $smtp.subject -Body "Your jobtitle is updated"
}
catch{
	Write-Host ("Failed to update " + $($user.name)) -ForegroundColor Red
}

这里的问题是,如果 Try 块中出现问题,我们只会收到更新失败的错误。但你不知道是哪一部分。也许用户已更新,但脚本无法发送到邮件。

这里更好的选择是将 Try 拆分为查找和更新用户,并使用 Try-Catch 创建另一个函数来发送电子邮件。

PowerShell 最后阻止

finally 块是可选的,因此您不需要每次都使用它。无论 Try 块的结果如何,finally 块内的代码始终都会执行。例如,您可以使用finally块来关闭连接,或者作为日志记录的一部分。

捕获终止和非终止错误

当谈到在 PowerShell 中捕获错误时,有一点非常重要,那就是非终止错误。这些错误不会终止(停止)脚本。默认情况下,catch 块无法捕获此类错误。

PowerShell 中的大多数 cmdlet 都是非终止的。如果您错误地使用它们,它们将输出一个错误,您将在控制台中看到红色的错误,但它们不会停止脚本。其原因是您的 PowerShell 配置文件中的默认 ErrorAction ,它设置为继续

# To show your default error action type
$ErrorActionPreference

采取以下示例,使用 Try Catch 块在 PowerShell 中打开一个不存在的目录:

try {
    dir "c:\some\non-existing\path"
    
}
catch {
    Write-host "Directory does not exist"
}

您期望看到“目录不存在”,但您却收到正常的红色错误消息。原因是不存在的路径不是终止错误,默认的错误操作是继续。

要捕获错误,您需要在操作后面添加 -ErrorAction Stop 参数。

try {
    dir "c:\some\non-existing\path" -ErrorAction stop
    
}
catch {
    Write-host "Directory does not exist"
}

另一种选择是在脚本或 PowerShell 会话开始时更改 ErrorActionPreference。但请记住,当您开始新会话时,首选项将重置以继续。

$ErrorActionPreference = "Stop"

Powershell尝试捕获异常

PowerShell 中的异常可以让您更好地处理错误。到目前为止,我们只使用了一个简单的 catch,它基本上可以捕获任何错误。这是一个很好的开始方式,但如果您想进一步改进 PowerShell 错误处理,那么您可以使用异常。

正如我在一开始提到的,Try Catch 块应该有至少一个 catch 块。这意味着我们可以有多个 catch 块来捕获不同的错误并以不同的方式处理它们。

如果我们以以下更新职位为例:

try{
	# Find the user to update
	$ADUser = Get-AzureAdUser -ObjectId $user.UserPrincipalName -ErrorAction Stop

	# Update the job title
	Set-AzureAdUser -ObjectId $ADUser.ObjectId -JobTitle $user.jobtitle -ErrorAction Stop
}
catch [Microsoft.Open.Azure.AD.CommonLibrary.AadNeedAuthenticationException]{
	# Catch a connection error
	Write-Warning "You need to Connect to AzureAD first"
}
catch [Microsoft.Open.AzureAD16.Client.ApiException] {
	# Catch the when we are unable to find the user
	Write-Warning "Unable to find the user"
}
Catch {
	Write-Warning "An other error occured"
}

例如,我们可以在此处执行以下操作:捕获尚未建立与 AzureAD 的连接时的错误,或者捕获无法在 AzureAD 中找到用户时的错误。我们通过为 catch 块定义异常来做到这一点。

这里困难的部分是找到需要捕获的异常。找到它们的唯一方法是运行脚本,并确保触发您想要捕获的错误。然后,您可以在错误消息或 $Error 变量中找到异常

[玩转系统] 如何在 PowerShell 中使用 Try、Catch、Finally

正如您在屏幕截图中看到的,我们可以在错误消息(1)中找到身份验证异常。另一种选择是查看 $Error 变量。如果您在错误发生后直接运行 $Error[0].Exception.GetType().FullName,那么您将获得可在 catch 块中使用的完整异常名称。

Powershell错误变量

让我们详细解释一下 PowerShell Error 变量。当 PowerShell 中发生错误时,它将被附加到 $error 变量中。该变量将包含 PowerShell 会话期间发生的所有错误。

除了 $error 之外,您还可以在 catch 块内使用 $._$PSitem 来显示有关错误的详细信息。

$error 变量非常有用,包含很多有关错误的信息。我们不仅可以使用这些信息来正确处理错误,还可以更好地通知用户。

查找错误的位置

当您编写较大的脚本时,了解导致错误的函数的确切位置会很方便。在错误变量中,您将找到 ScriptStackTrace。这将输出错误的确切位置和起源。

举个例子:

$ErrorActionPreference = "Stop"


Function OpenPath($path) {
    try {
        dir $path 
    }
    catch {
        Write-host "Directory does not exist" -ForegroundColor Red
        Write-Host $_.ScriptStackTrace
    }
}

OpenPath("c:\some\non-existing\path")

当您运行此代码时,您将获得以下堆栈跟踪:

[玩转系统] 如何在 PowerShell 中使用 Try、Catch、Finally

正如您所看到的,错误发生在 OpenPath 函数的第 6 行,该函数由第 15 行的脚本调用。

此类信息确实可以帮助您调试脚本。

显示正确的错误消息

您可以在 PowerShell Catch 块中编写自己的错误消息,但有时异常消息就足够了。

Function OpenPath($path) {
    try {
        dir $path -ErrorAction Stop
    }
    catch {
        Write-Host $_.Exception.Message -ForegroundColor Red
    }
}

#Outputs:
Cannot find path 'C:\some\non-existing\path' because it does not exist.

计算 PowerShell 中的错误

Error 变量的一个小功能,但有时非常方便,可以计算发生了多少个错误

$Error.count

清除PowerShell错误变量

error 变量包含大量信息,您可以使用 get-member cmdlet 查看 Error 变量的所有属性。我想指出的最后一件事是清除错误变量。当您尝试找到正确的异常时,在再次运行脚本之前清除变量确实很方便。

$Error.clear()

总结

PowerShell 中的 Try Catch 块可以帮助您编写更好的脚本,即使出现问题,脚本也可以执行您想要的操作。最困难的部分是编写良好的 catch 块,因为您需要弄清楚脚本中可能出现的问题。

我希望这篇文章能帮助您开始使用 Try-Catch 块,如果您有任何疑问,请在下面发表评论。

您可能还喜欢以下文章:

  • 使用 PowerShell 连接到 Exchange Online
  • 使用 PowerShell 为 Office 365 用户启用 MFA

您需要 登录账户 后才能发表评论

取消回复欢迎 发表评论:

关灯