Sql-Server

在 PowerShell 中使用 @ExpertMode = 1 執行 sp_AskBrent

  • February 5, 2016

我正在嘗試sp_AskBrent使用 PowerShell 從 PowerShell執行Invoke-SQLCmd並在變數中擷取其輸出:

$query = "EXEC SAIDBA.monitoring.sp_AskBrent @Seconds=10;"
$check = Invoke-Sqlcmd -ServerInstance $ServerInstance -Query $query 
            -ErrorAction Stop -ConnectionTimeout 3

使用ExpertMode = 0執行時,沒問題。

但是當以ExpertMode = 1執行時,我們注意到三件事:

  1. 它將每個數據輸出到外殼
  2. $check一片空白
  3. 它以以下錯誤結束:

Invoke-Sqlcmd:SQL PowerShell 中不允許出現重複的列名。要重複列,請使用 Column_Name AS New_Name 格式的重複列的列別名。

在行:1 字元:18

* $ check = Invoke-Sqlcmd -ServerInstance $ ServerInstance -Query $query -Er … * 類別資訊:語法錯誤:(:)$$ Invoke-Sqlcmd $$, SqlPowerShellSqlExecutionException * FullyQualifiedErrorId : DuplicateColumnNameErrorMessage, Microsoft.SqlServer.Management.PowerShell.GetScriptCommand

我認為有一種解決方法可以提供參數sp_AskBrent以將ExpertMode數據儲存到表中,然後從這些表中進行選擇,但我想確保無法在 PowerShell 中立即恢復所有內容。

不要低估布倫特的回答(儘管他有時在訓練中給出了一些好的答案)……

在 PowerShell 中,您可以執行返回多個數據集的查詢,但您不能使用它來執行此操作Invoke-Sqlcmd,因為它目前不是為它建構的。

您將有兩種選擇,使用 .NET 本機程式碼(例如System.Data.SqlClient)或使用可信賴的SMO. SMO如果我想包含伺服器屬性或其他可以訪問的東西,我傾向於簡單地選擇SMO

在上下文中,sp_AskBrent我花了幾分鐘將輸出建構到 HTML 報告中。此腳本的主要興趣點是,要處理多個數據集,您將ExecuteWithResults使用以下命名空間下可用的方法執行查詢:

  • Microsoft.SqlServer.Management.Smo.Server
  • Microsoft.SqlServer.Management.Smo.Database

database 您可以在此處查看使用 MSDN 上的命名空間的範例。在我的腳本中,我使用了Server命名空間。無論哪種方式都可以,但是如果您查看 MSDN 文章,ExecuteWithResults它將返回一個DataSet對象,並且該對象將包含一個DataTable. 數量DataTables基於您的程式碼返回的數據集數量。在布倫特程序的情況下,您將得到 5 DataTables。您可以在下面的程式碼中通過在循環$results.Count之前添加 in 來驗證這一點。foreach

現在這個腳本中的另一個注意事項是我選擇輸出到 HTML。如果需要,您可以選擇另一種格式,但將所有內容輸出到控制台是不可讀的。我還會注意到我添加了幫助資訊,因此Get-Help如果您需要查看參數的詳細資訊或提醒自己如何呼叫它,您可以針對腳本使用。

對於這個範例,我使用了來自 Pinal Dave 的一小段程式碼來在我的本地實例上生成一些 CPU 使用率。(否則程序沒有返回太多資訊)。

在此處輸入圖像描述

在此處輸入圖像描述

腳本

<#
   .SYNOPSIS
       Executes sp_AskBrent and outputs to HTML
   .DESCRIPTION
       Execute sp_AskBrent in normal or expert mode and outputs to an HTML.
   .PARAMETER server
       String. [REQUIRED] The SQL Server instance you wish to get results on.
   .PARAMETER timelimit
       Integer. Time used for @seconds parameter of sp_AskBrent
   .PARAMETER expertMode
       Switch. Just opts to have @ExpertMode = 1 for the query
   .PARAMETER sqlversion
       Integer. If on machine with multiple SQL Server tool versions installed, specify version.
   .PARAMETER outfile
       String. Set output file to generate HTML
   .EXAMPLE
   Run command in normal mode, which returns one dataset
   .\Script.ps1 -server MANATARMS\SQL12 -timelimit 5 -sqlversion 11 -outfile 'C:\temp\MyServer.html'
   .EXAMPLE
   Run command in expert mode, which returns multiple datasets
   .\Script.ps1 -server MANATARMS\SQL12 -timelimit 5 -expertMode -sqlversion 11 -outfile 'C:\temp\MyServer.html'
   .NOTES
   Does not check if sp_AskBrent is on the server before executing the query.
#>
[cmdletbinding()]
param(
   [Parameter(Mandatory=$true,Position=0)]
   [Alias("instance")]
   [string]
   $server,

   [Parameter(Mandatory=$false,Position=1)]
   [int]
   $timelimit = 10,

   [Parameter(Mandatory=$false,Position=2)]
   [switch]
   $expertMode,

   [Parameter(Mandatory=$false,Position=3)]
   [int]
   $sqlversion = 11,

   [Parameter(Mandatory=$false,Position=4)]
   [string]
   $outfile= 'C:\temp\Testing.html'
)

$HtmlTop = @"
<!DOCTYPE html>
<html>
<head>
<style>
   body { 
       background-color:white;
       font-family:Tahoma,Arial;
       font-size:10pt;
   }
   table {
       border-collapse: collapse;
   }
   th { 
       border:2px solid black;
       color:white;
       background-color: #0066FF;
       padding: 4px;
   }
       th.subhead {
           color:black;
           background-color: #8dbafc
       }
   td {
       border: 1px solid black;
       padding: 2px;
   }

</style>
</head>
<body>
<h2>Server Name: $($server)</h2>
<h3>Run Date: $(Get-Date)</h3>
"@

$HtmlTop | Out-File -FilePath $outfile -Force

if ($expertMode) {
   $askBrent = "EXEC sp_AskBrent @Seconds=$($timelimit), @ExpertMode=1"
}
else {
   $askBrent = "EXEC sp_AskBrent @Seconds=$($timelimit), @ExpertMode=0"
}

try { 
   Add-Type -AssemblyName "Microsoft.SqlServer.Smo,Version=$($sqlversion).0.0.0,Culture=neutral,PublicKeyToken=89845dcd8080cc91"
}
catch {
   Add-Type -AssemblyName "Microsoft.SqlServer.Smo"
}

$srv = New-Object 'Microsoft.SqlServer.Management.Smo.Server' $server

$results = $srv.ConnectionContext.ExecuteWithResults($askBrent);

foreach ($t in $results.Tables) {
   $t | Select-Object * -ExcludeProperty RowError, RowState, HasErrors, Table, ItemArray | ConvertTo-Html -As Table -Fragment | Out-String | Out-File -FilePath $outfile -Append
   ## This is just to get a break between tables ##
   "<hr>" | Out-File -FilePath $outfile -Append
}

引用自:https://dba.stackexchange.com/questions/122262