我正在实施一个新的过程,以利用扩展事件功能来审核成功和失败的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文件夹中。
有人可以帮我吗?
谢谢
答案 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();
}