如何捕获输出消息并将其保存到 powershell 和 SqlCmd 中的变量

How to capture output message and save it to variable in powershell and SqlCmd

我正在使用 powershell 代码 https://dba.stackexchange.com/a/254401/92058,它循环遍历实例上的每个数据库并使用 DBCC CheckDB sql 命令检查损坏。

如果检测到损坏(例如在这种情况下,DB 50Ways 上的页面已损坏),DBCC CheckDB 命令将输出一条消息(不是错误!)。

如您所见,正在处理数据库50Ways下面弹出消息,表明它发现了损坏的页面。

那么我如何才能只捕获这条消息(如果有的话)并将其保存到一个变量中,这样我就可以向自己发送电子邮件通知。

$ServerInstance = "myinstance" ## instance name 
$Databases = Invoke-SqlCmd -ServerInstance $ServerInstance -Database master -Query "SELECT [name] AS [Database] FROM sys.databases  ORDER BY 1 DESC;"

foreach ($DB in $Databases)
{
    Write-Output "Processing $($DB.Database)..."

    Invoke-SqlCmd -ServerInstance $ServerInstance -Database master -Query "DBCC CHECKDB ([$($DB.Database)]) WITH NO_INFOMSGS,PHYSICAL_ONLY;" -OutputSqlErrors:$true -Verbose
}
Write-Output "Complete."

输出如下所示:

Processing WideWorldImporters...
Processing tempdb...
Processing msdb...
Processing model...
Processing master...
Processing DBA...
Processing AdventureWorks2017...
Processing 50Ways...
Invoke-SqlCmd : Table error: Object ID 901578250, index ID 0, partition ID 
72057594043105280, alloc unit ID 72057594049527808 (type In-row data), page (1:312). 
Test (IS_OFF (BUF_IOERR, pBUF->bstat)) failed. Values are 133129 and -4.
Object ID 901578250, index ID 0, partition ID 72057594043105280, alloc unit ID 
72057594049527808 (type In-row data): Page (1:312) could not be processed.  See other 
errors for details.
CHECKDB found 0 allocation errors and 2 consistency errors in table 'ToLeaveYourLover' 
(object ID 901578250).
CHECKDB found 0 allocation errors and 2 consistency errors in database '50Ways'.
repair_allow_data_loss is the minimum repair level for the errors found by DBCC CHECKDB 
(50Ways).
At line:11 char:5
+     Invoke-SqlCmd -ServerInstance $ServerInstance -Database master -Q ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Invoke-Sqlcmd], SqlPowerShellSqlEx 
   ecutionException
    + FullyQualifiedErrorId : SqlError,Microsoft.SqlServer.Management.PowerShell.GetScr 
   iptCommand
 
Complete.

和图片一样,只需要在变量中捕获一条红色消息。

也尝试使用 TRY CATCH 块,但它根本没有捕捉到错误。

BEGIN TRY
   DBCC CHECKDB ([50Ways]) WITH NO_INFOMSGS,PHYSICAL_ONLY
END TRY
BEGIN CATCH
   SELECT 
          ERROR_MESSAGE() AS [Error Message]
         ,ERROR_LINE() AS ErrorLine
         ,ERROR_NUMBER() AS [Error Number]  
         ,ERROR_SEVERITY() AS [Error Severity]  
         ,ERROR_STATE() AS [Error State]  

END CATCH

这些只是您可以使用 CommonParameter -ErrorVariable 或使用自动变量 $Error 捕获的标准异常错误。

下面是一个使用ErrorVariable的例子。我们告诉 Invoke-SqlCmd 将遇到的任何错误存储在名为 'dbCheckErrors' 的变量中。我们稍后检查此变量 $dbCheckErrors 是否包含任何 ErrorRecords,如果包含,我们将所有异常消息收集到我们的 $errorCollection 数组中以供以后访问。完成数据库检查后,我们可以查看消息,将消息保存到文件中,或者两者都可以。

# Create an empty array to later capture error message in our loop
$errorCollection = @()
foreach ($DB in $Databases)
{
    Write-Output "Processing $($DB.Database)..."
    Invoke-SqlCmd -ErrorVariable 'dbCheckErrors' -ServerInstance '(localdb)\MSSQLLocalDB' -Database master -Query "DBCC CHECKDB ([$($DB.Database)]) WITH NO_INFOMSGS,PHYSICAL_ONLY;" -OutputSqlErrors:$true -Verbose 

    if ($dbCheckErrors) {
        # Do something with any errors here

        # Or just add the exception message(s) to a collection to handle later
        $errorCollection += $dbCheckErrors.Exception.Message
    }
}

# view the exception messages
$errorCollection

# save the exception messages to file
$errorCollection | Set-Content -Path '.\dbCheckErrors.log'