LogParser ADO.NET 数据提供程序






4.62/5 (9投票s)
本文介绍了如何将 Microsoft LogParser 的 SQL 功能与 ADO.NET 结合使用。

引言
LogParser DataProvider
是一个 ADO.NET 数据提供程序,它封装了 LogParser Microsoft 工具的 SQL 功能。因此,您可以使用 .NET Framework 的绑定功能,通过 dataset 和 datatable 来处理解析后的日志数据。
背景
Log parser 是一个强大而通用的工具,它提供对基于文本的数据(如日志文件、XML 文件和 CSV 文件)以及 Windows® 操作系统上的关键数据源(如事件日志、注册表、文件系统和 Active Directory®)的通用查询访问。您可以在 Microsoft 官方网站 此处下载。
Using the Code
要使用 LogParser DataProvider
,您必须先安装 Microsoft LogParser 工具。该项目是一个简单的自定义 DataProvider
实现,它使用 LogParser COM 接口。我遵循了 MSDN 上 Bob Beauchemin 撰写的文章“ADO.NET: Building a Custom Data Provider for Use with the .NET Data Access Framework”中的说明。该项目包含四个类的实现。
Connection
命令
DataReader
DataAdapter
本文附带了一个使用 LogParser DataProvider
的演示项目。在演示窗体中,用户可以编写和执行 SQL 语句,并在 dataGrid
中查看结果。
关注点
创建自定义数据提供程序时,“Connection”类是必需的,即使您实际上没有连接到数据源。其他类,例如 `Command` 类,需要 `Connection` 类才能实现基本功能。`DataAdapter` 在将 `DataTable` 填充到 `DataSet` 的过程中会调用 `Connection` 类的 `Open` 和 `Close` 方法。在我的实现中,这个类是空的;它只是一个与其它类一起使用的强类型类。
- “
Command
”类至少有两个用途。支持使用您选择的命令语言的命令,以直接影响数据存储。对于 LogParser,仅支持“SQL SELECT
”命令。 - “
DataAdapter
”类使用 `Command` 类将结果填充到 `DataSet` 中。 - “
DataReader
”类是我进行最多自定义的主要类。它用于处理 `Command` 的结果。它的方法允许使用者以仅向前的方式遍历一个或多个结果集中的行。它还提供了将这些行中列的数据获取到 .NET 类型变量中的方法。`LogParserDataReader` 类的 execute 方法使用 LogParser COM 包装器的 `ILogQuery` 接口执行 SQL 语句,并初始化一些内部数组,包含查询返回的列的名称、类型和大小。
internal void Execute(String command)
{
//create logparser object instance
_lp = new LogQueryClassClass();
//Execute the command
rs = _lp.Execute(command, null);
//logparser class does not return this information
_RecordsAffected = -1;
_fieldCount = rs.getColumnCount();
_cols.Clear();
_names.Clear();
_types.Clear();
_sizes.Clear();
//Iterate throw all columns
for (int i=0;i<_fieldCount;i++)
{
//Initialize the array that will contain fetched values
_cols.Add(null);
//Initialize names array with columns name
_names.Add(rs.getColumnName(i));
//Convert LogParser column type into ADO.NET column type
Type t = null;
Int32 s = 0;
switch (rs.getColumnType(i))
{
case 1:
t = typeof(int);
break;
case 2:
t = typeof(double);
break;
case 3:
t = typeof(string);
s = 1024;
break;
case 4:
t = typeof(DateTime);
break;
}
_types.Add(t);
//Initialize also size of column
_sizes.Add(s);
}
//Initialize the current row
_CurrentRow = -1;
//This statements create an IEnumerator class based on
//ILogRecordset used to iterate throw the recordset records.
_ie = new LogRecordsetEnumerator(rs);
_isClosed = false;
}
`GetSchemaTable()` 方法用于检索关于结果 `DataTable` 列的信息。最重要的属性是 `ColumnName`、`DataType`、`ColumnSize` 和 `ColumnOrdinal`。
public DataTable GetSchemaTable()
{
Debug.WriteLine("LogParserDataReader.GetSchemaTable", "LogParserDataReader");
DataTable tab = new DataTable();
// all of common, non "base-table" fields implemented
tab.Columns.Add("ColumnName", typeof(System.String));
tab.Columns.Add("ColumnSize", typeof(Int32));
tab.Columns.Add("ColumnOrdinal", typeof(Int32));
tab.Columns.Add("NumericPrecision", typeof(Int16));
tab.Columns.Add("NumericScale", typeof(Int16));
tab.Columns.Add("DataType", typeof(System.Type));
tab.Columns.Add("AllowDBNull", typeof(bool));
tab.Columns.Add("IsReadOnly", typeof(bool));
tab.Columns.Add("IsUnique", typeof(bool));
tab.Columns.Add("IsRowVersion", typeof(bool));
tab.Columns.Add("IsKey", typeof(bool));
tab.Columns.Add("IsAutoIncrement", typeof(bool));
tab.Columns.Add("IsLong", typeof(bool));
for (int i=0;i < _fieldCount;i++)
{
DataRow r = tab.NewRow();
r["ColumnName"] = _names[i];
r["ColumnSize"] = _sizes[i];
r["ColumnOrdinal"] = i;
r["NumericPrecision"] = 0;
r["NumericScale"] = 0;
r["DataType"] = _types[i];
r["AllowDBNull"] = false;
r["IsReadOnly"] = true;
r["IsUnique"] = false;
r["IsRowVersion"] = false;
r["IsKey"] = false;
r["IsAutoIncrement"] = false;
r["IsLong"] = false;
tab.Rows.Add(r);
}
return tab;
}
另一个有趣的方法是 `LogParserProvDataReader` 类的 `Read()` 函数。它用于读取阅读器的当前行,但它也被基类 `DBDataAdapter` 内部调用,以填充 `Dataset` 或 `DataTable`。
public bool Read()
{
Debug.WriteLine("LogParserDataReader.Read", "LogParserDataReader");
if (_ie != null)
{
bool notEOF = _ie.MoveNext();
if (notEOF == true)
{
_CurrentRow++;
ILogRecord lr = (ILogRecord)_ie.Current;
for (int i=0;i<_fieldCount;i++)
{
_cols[i] = lr.getValue(i);
}
}
return notEOF;
}
return false;
}
关于演示项目
演示项目是一个用 VB.NET 编写的 Windows 窗体应用程序,其中 `DataGrid` 在运行时绑定到一个 ADO.NET `Dataset`。
Imports Data.LogParser
Public Class Form1
Inherits System.Windows.Forms.Form
Private c As LogParserConnection
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
Initialize()
End Sub
#Region " Windows Form Designer generated code "...
Private Sub Initialize()
c = New LogParserConnection
c.Open()
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
'Execute the statement contained in the TextBox
Dim sql As String = Me.TextBox1.Text
If sql <> "" Then
Try
Dim da As LogParserDataAdapter = New LogParserDataAdapter(sql, c)
Dim dt As DataTable
dt = New DataTable
da.Fill(dt)
'bind to dataTable
Me.DataGrid1.DataSource = dt
Me.DataGrid1.Refresh()
Catch ex As Exception
MessageBox.Show(ex.Message & vbCrLf & ex.StackTrace)
End Try
End If
End Sub
End Class
下面是一个有用的查询,用于检查用户访问失败(来自 Microsoft 示例查询)。
SELECT
COUNT(EventID) AS TotalLogonFailures,
TO_LOWERCASE(EXTRACT_TOKEN(Strings,0,'|')) AS User,
TO_LOWERCASE(EXTRACT_TOKEN(Strings,1,'|')) AS Domain,
TO_LOWERCASE(EXTRACT_TOKEN(Strings,5,'|')) AS WorkStation,
CASE TO_INT(EXTRACT_TOKEN(Strings,2,'|'))
WHEN 2 THEN 'Interactive -
Intended for users who will be interactively using the machine,
such as a user being logged on by a terminal server,
remote shell, or similar process.'
WHEN 3 THEN 'Network - Intended for high performance servers
to authenticate clear text passwords.
LogonUser does not cache credentials for this logon type.'
WHEN 4 THEN 'Batch - Intended for batch servers,
where processes may be executing on behalf
of a user without their direct intervention;
or for higher performance servers that process many
clear-text authentication attempts at a time,
such as mail or web servers. LogonUser does not cache
credentials for this logon type.'
WHEN 5 THEN 'Service - Indicates a service-type logon.
The account provided must have the
service privilege enabled.'
WHEN 6 THEN 'Proxy - Indicates a proxy-type logon.'
WHEN 7 THEN 'Unlock - This logon type is intended for GINA DLLs
logging on users who will be interactively using the machine.
This logon type allows a unique audit record to be generated that
shows when the workstation was unlocked.'
WHEN 8 THEN 'NetworkCleartext - Windows 2000; Windows XP and
Windows Server 2003 family:
Preserves the name and password in the authentication packages,
allowing the server to make connections to
other network servers while impersonating the client.
This allows a server to accept
clear text credentials from a client, call LogonUser,
verify that the user can access the system
across the network, and still communicate with other servers.'
WHEN 9 THEN 'NewCredentials - Windows 2000;
Windows XP and Windows Server 2003 family:
Allows the caller to clone its current token and
specify new credentials for outbound connections.
The new logon session has the same local identity,
but uses different credentials for other
network connections.'
WHEN 10 THEN 'RemoteInteractive -
Terminal Server session that is both remote and interactive.'
WHEN 11 THEN 'CachedInteractive -
Attempt cached credentials without accessing the network.'
WHEN 12 THEN 'CachedRemoteInteractive -
Same as RemoteInteractive. This is used for internal auditing.'
WHEN 13 THEN 'CachedUnlock - Workstation logon'
ELSE EXTRACT_TOKEN(Strings,2,'|')
END AS Type
INTO DATAGRID
FROM \\%machine%\security
WHERE EventID IN (529)
GROUP BY User,Domain,WorkStation,Type
ORDER BY TotalLogonFailures DESC
增强功能
使用数据提供程序以编程方式提取安全审计数据,有助于创建自动审计过程,并结合 ADSI 功能,可以成为强大的风险管理工具。
历史
- 2007 年 5 月 11 日:首次发布