【问题标题】:Powershell try-catch...else?Powershell tr​​y-catch ...其他?
【发布时间】:2020-02-09 06:31:05
【问题描述】:

我了解 Powershell 中的 try-catch-finally,但是否有类似于 Python 的“else”子句,其中代码仅在没有错误时运行?

我正在编写一个脚本,该脚本在一个经常出现故障的站点上使用 invoke-webRequest。我使用 try-catch 来捕获 HTTP 错误。 我还希望只有在 invoke-webRequest 命令成功完成时才运行一段代码。

try{
    invoke-WebRequest -URI 'http://flakywebsite.com/site1' -Method GET
    invoke-WebRequest -URI 'http://flakywebsite.com/site2' -Method GET
    invoke-WebRequest -URI 'http://flakywebsite.com/site3' -Method GET
    }
catch{
    "This line will execute only if there is an error in the try block"
    }
else{
    "This line will execute only if there is NOT an error in the try block"
    }
finally{
    "This code will run regardless of whether there is or is not an error in the try block."
    }

我有这个解决方法。它使用 catch 块将通知附加到 $Error 变量:

try{
    invoke-WebRequest -URI 'http://flakywebsite.com/site1' -Method GET
    invoke-WebRequest -URI 'http://flakywebsite.com/site2' -Method GET
    invoke-WebRequest -URI 'http://flakywebsite.com/site3' -Method GET
    }
catch{
    $Error.add("An error occurred in the try loop."}
    }
if($Error[-1] -ne "An error occurred in the try loop."){
    "This code will run only if there is NOT an error in the try block.
    }

这行得通,但它非常难看。有没有更好的方法在 Powershell 中做到这一点?

【问题讨论】:

  • 也许你可以使用if(!$Error){ "An error didn't occur" }
  • Invoke-WebRequest 中发生的任何错误都应该(取决于你的$ErrorActionPreference ofc)触发切换到catch 块,所以你为什么不把else 块中的代码放在下面Invoke-WebRequest?

标签: powershell try-catch


【解决方案1】:

嗯,在你的 try-catch 中,你添加了许多不同的东西。最佳实践建议为您的每个 Invoke-Request 命令设置一个 try 块,因为您无法了解哪个站点创建了错误。但是你可以在你的代码下面添加一行。

try{
    invoke-WebRequest -URI 'http://flakywebsite.com/site1' -Method GET
    invoke-WebRequest -URI 'http://flakywebsite.com/site2' -Method GET
    invoke-WebRequest -URI 'http://flakywebsite.com/site3' -Method GET
    "This line will execute only if there is NOT an error in the try block"
    }
catch{
    "This line will execute only if there is an error in the try block"
    }
finally{
    "This code will run regardless of whether there is or is not an error in the try block."
    }

【讨论】:

    【解决方案2】:

    不,从 v7 开始,遗憾的是,PowerShell提供类似 Python 的 else 子句作为 try / catch 语句的一部分。


    一种选择是将 only-if-not-catch 代码放在 try 块的底部,在可能失败的命令之后 - 请参阅 Zafer Balkan's helpful answer

    如果不希望这样做,我建议使用以下成语作为解决方法

    # Make sure that even normally non-terminating errors trigger the
    # `catch` block below.
    # Note that the *first* error that occurs in the `try` block
    # will jump to the `catch` block right away - subsequent commands won't execute.
    $ErrorActionPreference = 'Stop'
    
    # Save the count of errors currently recorded in the automatic $Errors collection.
    $errCountBefore = $Error.Count
    
    try {
    
        invoke-WebRequest -URI 'http://flakywebsite.com/site1' -Method GET
        invoke-WebRequest -URI 'http://flakywebsite.com/site2' -Method GET
        invoke-WebRequest -URI 'http://flakywebsite.com/site3' -Method GET
    
    }
    catch {
        # Write a custom error to the $Error collection, as the *first* 
        # (most recent) item.
        # Note: If you want the error to also *display*, use `-ErrorAction Continue`.
        Write-Error -ErrorAction SilentlyContinue "An error occurred in the try loop: $_"
    }
    
    if ($errCountBefore -eq $Error.Count) { # No errors occurred.
      "This code will run only if there is NOT an error in the try block."
    }
    

    注意:如果您没有在 catch 块中写入错误,请使用您在 @987654333 中设置为 $true 的自定义 [bool] 变量,例如 $caught @block,然后测试if (-not $caught)


    至于你尝试了什么

    $Error.add("An error occurred in the try loop."}

    你不应该直接写信给$Error(这使得以下几点没有实际意义:不要添加字符串并且不要' t 追加到它存储的错误集合中),原因如下:

    $Error是PowerShell中所谓的automatic variable,一般表示PowerShell自己管理它,用户代码不应该直接修改它。

    关于$Error 的唯一例外是您可能希望清除到目前为止在会话中累积的错误集合,使用$Error.Clear()

    否则,PowerShell 管理$Error 如下:

    • 任何错误都会自动记录在$Error,按反向时间顺序(最近的在前)。

      • 唯一的例外是使用-ErrorAction Ignore 调用的命令和外部程序的stderr 输出。
    • $Error 仅包含 错误记录对象System.Management.Automation.ErrorRecord 类型的实例),它们提供有关每个错误的结构化详细信息。

    因此,为了在$Error 中记录错误,您的代码需要做的就是使用Write-Error 将错误写入错误流,或者使用@987654347 引发脚本终止错误@ 语句 - PowerShell 将在必要时将每个错误包装在 System.Management.Automation.ErrorRecord 实例中,并按时间倒序添加到 $Error 之前。

    【讨论】:

      猜你喜欢
      • 2011-10-10
      • 1970-01-01
      • 2015-12-14
      • 1970-01-01
      • 2022-12-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-29
      相关资源
      最近更新 更多