• 使用 PowerShell 将 Windows 转发事件导入 SQL Server


    在过去的几周里,我研究了多种解析Windows 转发事件并将其导入SQL Server 的方法:从使用 SSIS 到 LogParser 到 PowerShell,再到将链接服务器设置为“Forwarding Events.evtx”文件。

    最终,唯一有效的是 PowerShell 的 Get-WinEvent cmdlet。然后,它只适用于我的一个特定情况——如果事件是在 Windows 2012 服务器上收集和解析的。截至今天,Get-WinEvent 中存在一个未解决的错误,该错误通常导致 NULL LevelDisplayName、Message 和 TaskDisplayName 列。我在 Win2k8 R2 服务器和 Win 8 工作站上复制了下面的确切代码,并反复遇到 NULLs 问题。但是,您的结果可能会有所不同,因为一些用户报告通过在 Win2k8 R2 Server 中调整一些东西取得了成功。

    因此,启动一个 Windows 2012 机器,设置您的 SQL Server,让我们开始吧:

    SQL 部分

    查看Get-WinEvent返回的数据后,我发现以下列最有用:ID、LevelDisplayName、LogName、MachineName、Message、ProviderName、RecordID、TaskDisplayName、TimeCreated。然后我使用这些列创建了一个表:

    1. CREATE DATABASE EventCollections
    2. GO
    3. USE EventCollections
    4. GO
    5. -- the table name loosely relates to the name of my Win Event Subscription name
    6. CREATE TABLE [dbo].[GeneralEvents](
    7. [Id] [int] NULL,
    8. [LevelDisplayName] [varchar](255) NULL,
    9. [LogName] [varchar](255) NULL,
    10. [MachineName] [varchar](255) NULL,
    11. [Message] [varchar](max) NULL,
    12. [ProviderName] [varchar](255) NULL,
    13. [RecordID] [bigint] NULL,
    14. [TaskDisplayName] [varchar](255) NULL,
    15. [TimeCreated] [smalldatetime] NULL
    16. )
    17. -- Create Unique Clustered Index with IGNORE_DUPE_KEY=ON to avoid duplicates in sqlbulk imports
    18. CREATE UNIQUE CLUSTERED INDEX [ClusteredIndex-EventCombo] ON [dbo].[GeneralEvents]
    19. (
    20. [RecordID] ASC,
    21. [MachineName] ASC,
    22. [LogName] ASC
    23. ) WITH (IGNORE_DUP_KEY = ON)
    24. GO

    为了避免在每小时导入期间出现重复,我使用 IGNORE_DUP_KEY = ON 在 3 列上的唯一索引创建了表:RecordID、MachineName 和 LogName。

    接下来,我必须决定如何将数据从 PowerShell 获取到 SQL Server。在阅读了sqlservercentral.comtechnet之后,我决定使用sqlbulkcopy.

    PowerShell 部分

    转发事件是一件棘手的事情。出于某种原因,通常使用FilterHasTable过滤 Get-WinEvent 结果的方式一直返回结果Get-WinEvent :未找到与指定选择条件匹配的事件。我发现许多其他人也遇到了这个问题,当人们尝试使用 LogParser 时也发生了类似的错误。毕竟,我对 FilterXML 的工作没有太大希望,但它确实做到了!因此,我们将在执行初始导入后使用它。

    这是initial import在转发事件中收集所有事件的代码。

    1. $events = Get-WinEvent ForwardedEvents | Select-Object ID, LevelDisplayName, LogName, MachineName, Message, ProviderName, RecordID, TaskDisplayName, TimeCreated
    2. $connectionString = "Data Source=sqlserver;Integrated Security=true;Initial Catalog=EventCollections;"
    3. $bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $connectionString
    4. $bulkCopy.DestinationTableName = "GeneralEvents"
    5. $dt = New-Object "System.Data.DataTable"
    6. # build the datatable
    7. $cols = $events | select -first 1 | get-member -MemberType NoteProperty | select -Expand Name
    8. foreach ($col in $cols) {$null = $dt.Columns.Add($col)}
    9. foreach ($event in $events)
    10. {
    11. $row = $dt.NewRow()
    12. foreach ($col in $cols) { $row.Item($col) = $event.$col }
    13. $dt.Rows.Add($row)
    14. }
    15. # Write to the database!
    16. $bulkCopy.WriteToServer($dt)

    您可能已经注意到我手动构建了一个数据表,而不是使用Out-DataTable.ps1,这似乎是粉丝的最爱。我觉得上面的代码让事情变得更加整洁,性能仍然相当不错。

    由于事件收集是一个持续的事情,您可能希望定期导入它们。我通过右键单击事件查看器中的转发事件->过滤当前日志...->记录:(更改为一小时)->单击顶部的 XML 选项卡->复制/粘贴->瞧,构建了必要的 XML 查询。

    实际上,使用这个查询的语法,我找到了 FilterHashTable 的语法,但是让 GUI 构建我的查询很容易,所以我坚持了下来。这是hourly import您可以在任务计划程序中设置的代码。

    1. # While this script is intended to run on an hourly basis, the filter is set for going back 65 minutes.
    2. # This allows the script to run for 5 minutes without any missing any events. Because we setup the
    3. # table using the IGNORE_DUPE_KEY = ON, duplicate entries are ignored in the database.
    4. $xml = @'
    5. '@
    6. $events = Get-WinEvent -FilterXml $xml | Select-Object ID, LevelDisplayName, LogName, MachineName, Message, ProviderName, RecordID, TaskDisplayName, TimeCreated
    7. $connectionString = "Data Source=sqlserver;Integrated Security=true;Initial Catalog=EventCollections;"
    8. $bulkCopy = new-object ("Data.SqlClient.SqlBulkCopy") $connectionString
    9. $bulkCopy.DestinationTableName = "GeneralEvents"
    10. $dt = New-Object "System.Data.DataTable"
    11. # build the datatable
    12. $cols = $events | select -first 1 | get-member -MemberType NoteProperty | select -Expand Name
    13. foreach ($col in $cols) {$null = $dt.Columns.Add($col)}
    14. foreach ($event in $events)
    15. {
    16. $row = $dt.NewRow()
    17. foreach ($col in $cols) { $row.Item($col) = $event.$col }
    18. $dt.Rows.Add($row)
    19. }
    20. # Write to the database!
    21. $bulkCopy.WriteToServer($dt)

    运气好的话,您的 SQL 输出应该如下所示:

     

  • 相关阅读:
    Synchronized锁1
    打patch 命令
    一篇文章掌握整个JVM,JVM超详细解析!!!
    Linux查看防火墙状态及开启关闭命令-转载记录
    第十二章总结
    岭回归和LASSO回归
    f-string 格式化字符串的用法
    Java面试题:如何在Java中进行代码优化以提高性能?
    Linux(Centos7)OpenSSH漏洞修复,升级最新openssh-9.7p1
    坚鹏:浙江农商联合银行同业核心产品解读与差异化分析培训第7期
  • 原文地址:https://blog.csdn.net/allway2/article/details/126141105