将扩展事件结果导入到SQL Server表

时间:2018-09-10 12:57:54

标签: c# sql-server powershell

我正在实施一个新的过程,以利用扩展事件功能来审核成功和失败的SQL Server登录。我已经设置了扩展事件来监视成功和失败的登录,并将其结果发送到.xel文件中。但是,查询这些.xel文件以查看数据似乎很麻烦。最好将.xel文件数据导入到SQL Server表中。我找到了可以用于导入数据的PowerShell脚本(http://www.sqlservercentral.com/articles/PowerShell/160582/),但是在使数据正常工作时遇到了问题。我设置了一个测试扩展事件来监视rpc_completed和sql_batch_completed事件,我相信这些事件将显示已运行了哪些t-sql语句以及运行它们的用户。下面的脚本是专门为那些事件编写的,旨在按照我的解释导入数据,但是我无法使其正常工作。

有人知道为什么我的PowerShell脚本无法加载Microsoft.SqlServer.XE.Core.dll程序集吗?

这是我的脚本–

########Powershell cmdlet to load XE#######



 Function Shred-XElogs{
  param(
  [Parameter(Position=0, Mandatory=$true)] [string] $filewithPath,
  [Parameter(Position=1, Mandatory=$true)] [string] $servername,
  [Parameter(Position=2, Mandatory=$true)] [string] $fileName
  )
  Try
  {
  #Load the required assemblies
  $dllpath = "C:\Program Files\Microsoft SQL 

Server\120\Shared\Microsoft.SqlServer.XEvent.Linq.dll"
      if(([appdomain]::currentdomain.getassemblies() | Where {$_.Location -match "Microsoft.SqlServer.XEvent.Linq.dll"}) -eq $null)
       {
         Write-Host "Assembly not found. Loading it from $dllpath" `r`n
         [System.Reflection.Assembly]::LoadFrom($dllpath)
       }
  else
       {
        write-host "Assembly is already loaded." `r`n
       }
  [System.Reflection.Assembly]::LoadFrom($dllpath)
  #create data table
  $dt = New-Object System.Data.Datatable
  #Define Columns
  $server_name = New-Object system.Data.DataColumn 'server_name',([string])
  $xe_load_date = New-Object system.Data.DataColumn 'xe_load_date',([DateTime])
  $start_date = New-Object system.Data.DataColumn 'start_date',([DateTime])
  $end_time = New-Object system.Data.DataColumn 'end_time',([datetime])
  $text_data = New-Object system.Data.DataColumn 'text_data',([string])
  $duration = New-Object system.Data.DataColumn 'duration',([int64])
  $logicalreads = New-Object system.Data.DataColumn 'logicalreads',([int64])
  $physicalreads = New-Object system.Data.DataColumn 'physicalreads',([int])
  $EndResult = New-Object system.Data.DataColumn 'EndResult',([int])
  $RowCount = New-Object system.Data.DataColumn 'RowCount',([int])
  $ObjectName = New-Object system.Data.DataColumn 'ObjectName',([string])
  $writes = New-Object system.Data.DataColumn 'writes',([int])
  $CPU = New-Object system.Data.DataColumn 'CPU',([int64])
  $event_name = New-Object system.Data.DataColumn 'event_name',([string])
  $database_id = New-Object system.Data.DataColumn 'database_id',([int])
  $hostname = New-Object system.Data.DataColumn 'hostname',([string])
  $application_name = New-Object system.Data.DataColumn 'application_name',([string])
  $login_name = New-Object system.Data.DataColumn 'login_name',([string])
  $hostname = New-Object system.Data.DataColumn 'hostname',([string])
  $spid = New-Object system.Data.DataColumn 'spid',([int])
  $xe_log_file = New-Object system.Data.DataColumn 'xe_log_file',([string])
  # create columns
  [void]$dt.Columns.Add($server_name)
  [void]$dt.Columns.Add($xe_load_date)
  [void]$dt.Columns.Add($start_date)
  [void]$dt.Columns.Add($end_time)
  [void]$dt.Columns.Add($text_data)
  [void]$dt.Columns.Add($duration)
  [void]$dt.Columns.Add($logicalreads)
  [void]$dt.Columns.Add($physicalreads)
  [void]$dt.Columns.Add($EndResult)
  [void]$dt.Columns.Add($RowCount)
  [void]$dt.Columns.Add($ObjectName)
  [void]$dt.Columns.Add($writes)
  [void]$dt.Columns.Add($CPU)
  [void]$dt.Columns.Add($event_name)
  [void]$dt.Columns.Add($database_id)
  [void]$dt.Columns.Add($hostname)
  [void]$dt.Columns.Add($application_name)
  [void]$dt.Columns.Add($login_name)
  [void]$dt.Columns.Add($spid)
  [void]$dt.Columns.Add($xe_log_file)
  $events = New-Object Microsoft.SqlServer.XEvent.Linq.QueryableXEventData($filewithPath)
  $events | % {
      $currentEvent = $_
  $row = $dt.NewRow()
  $audittime = Get-Date
  $row.server_name = $servername
  $row.xe_load_date = [DateTime] $audittime
  $row.end_time = $currentEvent.Timestamp.LocalDateTime
  $row.duration = $currentEvent.Fields["duration"].Value
  $row.logicalreads = $currentEvent.Fields["logical_reads"].Value
  $row.physicalreads = $currentEvent.Fields["physical_reads"].Value
  $row.EndResult = $currentEvent.Fields["result"].Value.Key
  $row.RowCount = $currentEvent.Fields["row_count"].Value
  $row.ObjectName = $currentEvent.Fields["object_name"].Value
  $row.writes = $currentEvent.Fields["writes"].Value
  $row.CPU = $currentEvent.Fields["cpu_time"].Value
  $row.event_name = $currentEvent.name
  $row.database_id = $currentEvent.Actions["database_id"].Value
  $row.hostname = $currentEvent.Actions["client_hostname"].Value
  $row.application_name = $currentEvent.Actions["client_app_name"].Value
  $row.login_name = $currentEvent.Actions["server_principal_name"].Value
  $row.spid = $currentEvent.Actions["session_id"].Value
  $row.xe_log_file = $fileName
  if($currentEvent.name -eq 'sql_batch_completed') {$row.text_data = $currentEvent.Fields["batch_text"].Value}
  else {$row.text_data = $currentEvent.Fields["statement"].Value}
  $dt.Rows.Add($row)
  }
  $cn = new-object System.Data.SqlClient.SqlConnection("Data Source=(servername);Integrated Security=SSPI;Initial Catalog=AuditTest");
  $cn.Open()
  $bc = new-object ("System.Data.SqlClient.SqlBulkCopy") $cn
  $bc.BulkCopyTimeout = 1200 #you can increase if required
  $bc.DestinationTableName = "dbo.xe_audit_collection"
  [void]$bc.ColumnMappings.Add("server_name",$dt.Columns.ColumnName[0])
  [void]$bc.ColumnMappings.Add("xe_load_date",$dt.Columns.ColumnName[1])
  [void]$bc.ColumnMappings.Add("end_time",$dt.Columns.ColumnName[3])
  [void]$bc.ColumnMappings.Add("text_data",$dt.Columns.ColumnName[4])
  [void]$bc.ColumnMappings.Add("duration", $dt.Columns.ColumnName[5])
  [void]$bc.ColumnMappings.Add("logicalreads",$dt.Columns.ColumnName[6])
  [void]$bc.ColumnMappings.Add("physicalreads",$dt.Columns.ColumnName[7])
  [void]$bc.ColumnMappings.Add("EndResult",$dt.Columns.ColumnName[8])
  [void]$bc.ColumnMappings.Add("RowCount",$dt.Columns.ColumnName[9])
  [void]$bc.ColumnMappings.Add("ObjectName",$dt.Columns.ColumnName[10] )
  [void]$bc.ColumnMappings.Add("writes",$dt.Columns.ColumnName[11])
  [void]$bc.ColumnMappings.Add("CPU",$dt.Columns.ColumnName[12])
  [void]$bc.ColumnMappings.Add("event_name",$dt.Columns.ColumnName[13] )
  [void]$bc.ColumnMappings.Add("database_id",$dt.Columns.ColumnName[14])
  [void]$bc.ColumnMappings.Add("hostname",$dt.Columns.ColumnName[15] )
  [void]$bc.ColumnMappings.Add("application_name", $dt.Columns.ColumnName[16])
  [void]$bc.ColumnMappings.Add("login_name",$dt.Columns.ColumnName[17])
  [void]$bc.ColumnMappings.Add("spid",$dt.Columns.ColumnName[18])
  [void]$bc.ColumnMappings.Add("xe_log_file",$dt.Columns.ColumnName[19] )
  $bc.WriteToServer($dt)
  write-host " $($dt.rows.count) Rows have been transferred to SQL Server destination"`r`n
  $cn.Close()
  $events.Dispose() 
  $result = "`n Loading of file $XEFilePath complete! `n"
  }
  Catch
  {
      $result = $_.Exception
      $FailedItem = $_.Exception.ItemName

  }
  return $result
  }
  #### Load your First File #####
  $XEFilePath = "C:\Extended Event Audit Logs\RPC_competed and sql_batch_completed\RPC_competed and sql_batch_completed.xel"  ## file location
  $server = "(servername)"   ## server name, you are collecting XE data
  $XEFile = "RPC_competed and sql_batch_completed.xel"  ## XE File Name
  Shred-XElogs -filewithPath $XEFilePath -servername $server -fileName $XEFile

这是我收到的错误消息-

“找不到程序集。从C:\ Program Files \ Microsoft SQL Server \ 120 \ Shared \ Microsoft.SQLServer.XEvent.Linq.dll加载该程序集”

“带有” 1“参数的异常调用” .ctor“:”无法加载文件或程序集'Microsoft.SQLServer.XE.Core,版本= 12.0.0.0,Culter =中性,PublicKeyToken = 89845dcd8080cc91'或它的依赖项之一。系统找不到指定的文件。

我确保Microsoft.Sqlserver.XE.Core.dll文件存储在C:\ Program Files \ Microsoft SQL Server \ 120 \ Shared文件夹中。

有人可以帮我吗?

谢谢

1 个答案:

答案 0 :(得分:0)

如果要为此使用C#,则不需要Powershell。只需使用fn_xe_file_target_read_file查询.xel文件,然后将结果存储在表中即可完成此操作。下面的示例基于与自旋锁相关的扩展事件,它将删除结果表(如果存在)然后创建它。当然,您可能希望将其修改为通过删除DROP / SELECT INTO或仅删除保存结果的表TRUNCATE而不丢弃过去的结果。

 string sqlQuery = @" if (OBJECT_ID(N'YourDatabase.dbo.XE_Output') is not null)
           begin
           drop table YourDatabase.dbo.XE_Output
           end

           select rf.object_name, 
           cast(rf.event_data as xml).value('(//data/text)[1]', 'nvarchar(100)') as SpinlockType,
           cast(rf.event_data as xml).value('(//data)[1]', 'nvarchar(250)') as SpinlockAddress,
           cast(rf.event_data as xml).value('(//data)[2]', 'nvarchar(250)') as Worker,
           cast(rf.event_data as xml).value('(//data/value)[3]', 'nvarchar(100)') as BackoffCount,
           cast(rf.event_data as xml).value('(//data/value)[4]', 'nvarchar(100)') as Duration,
           xp.name as Package, xp.description as PackageDescription, rf.file_name,
           cast(rf.event_data as xml) as EventInfo
           into dbo.XE_Output
            from sys.fn_xe_file_target_read_file('C:\Test\YourOutputFile.xel', null, null, null) rf
           left join sys.dm_xe_packages xp on rf.package_guid = xp.guid";


string connString = "Data Source=localhost; Initial Catalog=YourDatabase; Integrated Security=SSPI;";
            using (SqlConnection conn = new SqlConnection(connString))
            {

                SqlCommand sqlCmd = new SqlCommand(sqlQuery, conn);
                sqlCmd.Connection.Open();
                sqlCmd.ExecuteNonQuery();

            }