【问题标题】:How to catch only SQL timeout errors in PowerShell?如何在 PowerShell 中仅捕获 SQL 超时错误?
【发布时间】:2020-05-23 00:06:00
【问题描述】:

我正在尝试仅捕获 PowerShell 5.1 脚本中的超时错误。错误打印出执行超时,但是当我打印出错误名称时,它返回[Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException]。这会捕获超时错误,但也会捕获其他错误。有没有办法只指定超时错误?

try
{
    $results1 = Invoke-Sqlcmd -Query $query -ConnectionString $connectionString
}
Catch [Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException] 
{
    Write-Output "Timeout error. Try again"
}

没有catch的错误

Invoke-Sqlcmd:执行超时已过期。在操作完成之前超时时间已过或服务器没有响应。

【问题讨论】:

  • 如果所有错误都返回相同的错误类型,我不知道如何让 Catch 识别它。可能能够使用扩展的错误信息和字符串解析将它们拆分在 catch 中,但这非常笨拙。我有兴趣看看是否有更好的方法。
  • 探索您的 $Error[0] 变量以获取您可以评估的特定内容:$Error[0].CategoryInfo.Category、$Error[0].CategoryInfo.Reason 等。使用 Get-有 $Error[0] 的成员可帮助探索。你会发现一些独特的东西。一旦你这样做了,在你的 Catch 块中放置一个 If 语句,条件是有意义的。
  • 尝试添加-ErrorAction Stop 使错误成为终止错误。此外,添加另一个 Catch {} 块(不要指定错误类型)来处理发生的任何其他终止错误。

标签: powershell exception timeout powershell-5.0 invoke-sqlcmd


【解决方案1】:

这是我上述评论的一个示例,可能会有所帮助。

try {
    [System.Void](New-Item -Path $LogPath -ItemType Directory -ErrorAction Stop)
} catch {
    If ($Error[0].CategoryInfo.Category -eq 'PermissionDenied' -or
        $Error[0].CategoryInfo.Reason -eq 'UnauthorizedAccessException') {
        Write-Output -InputObject "Please check that you have access to create a directory."
    } Else {
        Write-Output -InputObject "An error has occurred: $($Error[0].Exception.Message)."
    } # End If-Else.
} # End try-catch.

【讨论】:

    【解决方案2】:

    我找不到[SqlPowerShellSqlExecutionException] 类的任何文档,但是,通过downloading 并检查SqlServer 模块(特别是Microsoft.SqlServer.Management.PSSnapins 程序集),我发现异常类直接派生来自[Exception](所以没有一个通用的SQL异常类型,你可以用catch代替)并且只包含一个名为SqlError[SqlError]类型的属性。

    不幸的是,查看该文档并没有一个很好的枚举属性来描述各种潜在错误,但我确实看到有一个Number property。我有点困惑该页面上表格的最后一列是什么意思,但如果你像这样写你的catch 块......

    Catch [Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException] 
    {
        # Error number specified at https://docs.microsoft.com/dotnet/api/system.data.sqlclient.sqlerror.number#remarks
        if ($_.Exception.SqlError.Number -eq -2)
        {
            Write-Output "Timeout error. Try again"
        }
    }
    

    ...或者像这样...

    Catch [Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException] 
    {
        # Error number specified at https://docs.microsoft.com/dotnet/api/system.data.sqlclient.sqlerror.number#remarks
        if ($_.Exception.SqlError.Number -eq 258)
        {
            Write-Output "Timeout error. Try again"
        }
    }
    

    ...这将允许您专门针对超时错误。或者您可能需要检查这两个错误号。请参阅Database Engine Events and Errors 以获取要匹配的冗长错误编号列表,并考虑像这样编写catch 块来检查Number 的超时错误...

    Catch [Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException] 
    {
        $_.Exception.SqlError | Select-Object -Property 'Number', 'Message'
    }
    

    还有一个SqlError.Message property,所以作为最后的手段,你总是可以做这样的事情......

    Catch [Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException] 
    {
        #TODO: Is $_.Exception.SqlError.Message...
        #    - ...the same string as $_.Exception.Message ?
        #    - ...a substring of     $_.Exception.Message ?
        #    - ...more specific than $_.Exception.Message ?
        if ($_.Exception.SqlError.Message -eq 'Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.')
        {
            Write-Output "Timeout error. Try again"
        }
    }
    

    顺便说一句,虽然Write-Output 可能会实现将文本写入控制台的目标,但如果您的意图是向用户提供反馈,那么Write-HostWrite-InformationWrite-Warning 会更合适cmdlet。见PowerShell difference between Write-Host and Write-Output?

    【讨论】:

      猜你喜欢
      • 2015-03-07
      • 1970-01-01
      • 2023-02-13
      • 2013-08-18
      • 2016-01-21
      • 1970-01-01
      • 1970-01-01
      • 2018-01-08
      • 2012-07-21
      相关资源
      最近更新 更多