准备数据
创建 DirectAccess 健康报告时,提取所需数据时的主要困难是事件日志 CSV 格式是基于数据字符串的。在 GUI 中,这些数据需要隔行转换为静态字符串,以描述每个数据字段的含义。数据字符串包含所有对 DirectAccess 健康报告有意义的信息,包括用户名、计算机名称、策略组名称和 IP 地址。
数据字符串连成单个 CSV 字段,最终形成单个 SQL 列(还是字符串)。各个字符串之间用“|”字符分隔。一种可行的方法是在数据导入 SQL 之前或之后立即对字符串进行标记化。但是,我们的选择是在数据导入 SQL 后进行分析,然后提取所需的几个特定数据条目,再用这些条目填充独立的 SQL 表。
使用与 T-SQL 匹配的字符串模式完成此任务非常困难。作为备用方法,我们使用了以前的 MSDN 杂志文章正则表达式使模式匹配和数据提取变得更容易中介绍的方法:使用 C# 实现用户定义的 SQL 函数,特别是针对基于正则表达式的模式匹配。
使用 Visual Studio 2008,我们几乎完全遵照了该文中介绍的步骤,当然其他文档中有关使用 Visual Studio 开始 SQL 和 CLR 集成的介绍也很有帮助。另外,由于正则表达式 (RegEx) 本身的复杂性,因此参考有关正则表达式的文档也会有所帮助,特别是有关分组的内容,因为这是 MSDN 杂志文章中的示例代码所采用的方法。
以下示例代码就是 SQL 用户定义函数的源代码,该函数使我们的 SELECT 语句具备了正则表达式功能。此函数称为 RegexGroup,与 MSDN 杂志文章中介绍的函数一样。我们对函数主体的前两行进行了一处修改,以便检查 NULL 输入值。在加入这两行之前,我们遇到了无数的异常,因为有几个 SQL 帮助程序表的列(此处介绍的)都是 NULL 值:
复制代码
usingSystem;
usingSystem.Data;
usingSystem.Data.SqlClient;
usingSystem.Data.SqlTypes;
usingMicrosoft.SqlServer.Server;
usingSystem.Text.RegularExpressions;
publicpartialclassUserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
publicstaticSqlChars RegexGroup(
SqlChars input, SqlString pattern, SqlString name)
{
if (true == input.IsNull)
returnSqlChars.Null;
Regex regex = newRegex(pattern.Value, Options);
Match match = regex.Match(newstring(input.Value));
returnmatch.Success ?
newSqlChars(match.Groups[name.Value].Value) : SqlChars.Null;
}
};
以下 SQL 命令创建并填充两个帮助程序表,表中包含使用正则表达式从初始数据集中提取的字符串:
复制代码
/* Create the User-Computer-Address mapping helper table */
/* This step should only be performed once per data set */
CREATE TABLE UserComputerAndAddr
(
[RowN] int null,
[UserName] varchar(1023) null,
[ComputerName] varchar(1023) null,
[Address] varchar(1023) null
)
/* Populate the User-Computer-Address table */
/* This step should only be performed once per data set */
INSERT INTO UserComputerAndAddr(RowN, UserName, ComputerName, Address)
SELECT RowNumber,
dbo.RegexGroup([Strings],N'(?
dbo.RegexGroup([Strings],N'(?
dbo.RegexGroup([Strings],N'(?
FROM [NapDa].[dbo].[DaSasTable]
/* Create the Computer-Health mapping helper table */
/* This step should only be performed once per data set */
CREATE TABLE ComputerHealth
(
[RowN] int null,
[TimeGenerated] datetime null,
[EventType] int null,
[ComputerName] varchar(1023) null
)
/* Populate the Computer-Health mapping table */
/* This step should only be performed once per data set */
INSERT INTO ComputerHealth(RowN, TimeGenerated, EventType, ComputerName)
SELECT RowNumber,
TimeGenerated,
EventType,
dbo.RegexGroup([Strings],N'REDMOND\\(?
FROM [NapDa].[dbo].[HraSystemEventsTable]
仔细研究第一个 SELECT 语句以及它对 RegexGroup 函数(该函数通过我们介绍的技术安装)的使用,有助于了解字符串模式。图 3 详细介绍了我们定义的三个正则表达式模式。
图 3 使用 SQL 命令定义的三个正则表达式模式。
正则表达式模式 注意
用户名示例:ichiro@redmond.corp.microsoft.com
计算机名称示例:dan-dev-1@redmond.corp.microsoft.com
请注意,在此模式中我们明确排除了与 DirectAccess 服务器自身的匹配。
IPv6 地址例如:2001:0:4137:1f6b:8c8:2f30:e7ed:73a8
· 此模式不会匹配所有有效的 IPv6 地址。如果您要在其他上下文中使用,则需要增强此模式。
· 尽管 Strings 列中包含其他嵌入式 IPv6 地址字段,但客户端地址可能是唯一与此模式匹配的地址。如果您在查询中遇到了意外的地址,您可能需要重新访问此地址。
这些正则表达式共同创建了一个表,这个表由用户、计算机和地址信息组成。这些信息来自 DaSasTable 中的每一行(即从 DirectAccess 计算机导出的 IPsec SA 事件)。
创建并填充 UserComputerAndAddr 表后,会创建第二个表,用于将计算机名称与 HraSystemEventsTable 表中每一行的事件类型进行对应。如果您查看计算机名称的模式,您会发现在此日志中,计算机名称的格式不同于 DirectAccess 日志中的格式。在本例中,我们搜索 REDMOND\dan-dev-1 这样的字符串。图 4 详细介绍了 EventType 字段中可能存在的不同事件。
图 4 EventType 字段中可能存在的事件类型。
事件类型 | 说明 |
0 | 成功。计算机提交了健康的 NAP 合规声明。 |
1 | 失败。计算机不符合 NAP 策略。 |
在此部署方案的健康报告中,我们应该只会看到事件类型 0,这是因为 NAP 是在强制模式下使用的。正如您将在下文中看到的,我们还要筛选成功的 IPsec 安全关联。如果客户端不合规,它应该不能获取有效的 IPsec 证书并建立 SA。另一方面,如果您的组织已经用报告模式部署了 NAP,您将看到有一些不合规的计算机进行了连接。连接到网络的合规计算机与不合规计算机的相对比例将是报告中的一项重要统计信息。
注意:在创建表来容纳正则表达式的结果时,我们建议您使用永久的 SQL 表。如果您使用临时表(就像我们在下一步所演示的),正则表达式查询的速度将会变慢。