Windows PowerShell字符串理论

Don Jones

目录

一个真实的案例
复杂的匹配项
这是一个包含字符串的世界

每当我在 Tech•Ed 或 TechMentor 等会议上演讲时,我都习惯发出一些公告,通常它们会帮助用户记住一些事物(例如,Windows PowerShell)的关键点。我的最新公告是,“如果您在 Windows PowerShell 中解析字符串,那么您是在犯错误。”

它出自我对作为面向对象外壳的 Windows PowerShell™ 的观点。如果您是要将服务列表转储为文本文件,然后再对该文本文件进行解析以了解启动了哪些服务(或类似的工作),您的工作量一定非常大。对于基于文本的 OS(如 UNIX),这是一种有效的方法,但 Windows PowerShell(以及 Windows® 本身)可让您以一种更为有效的方式使用对象。

甚至您自己的脚本都应该生成对象(而非格式化文本),以便此外壳的各种格式、筛选、导出和其他命令可用来处理来自您脚本的输出。(在我 2008 年 7 月的 Windows PowerShell 专栏中,您可以阅读有关自定义对象作为脚本输出这一概念的更多信息。)

最近在奥兰多举办的 TechMentor 会议上,我的一名学生 Fla. 提醒我几乎所有规则(尤其是常用规则)都有一些例外。“在 IIS 日志文件中查找内容会怎样?在这种情况下您完全不必解析文本吗?”

嗯,是的。值得庆幸的是,Windows PowerShell 在解析文本的字符串方面也不示弱,类似它在对象友好方面的表现。既然您提到了这一方面,IIS 日志文件、防护墙日志文件及其他基于文本的日志可以充当完美的示例。

一个真实的案例

实际情况是,我需要为我服务的公司解析一组防火墙日志文件。一位员工被发现访问了一些不适宜的网站,在后续调查过程中,人力资源部门需要一个有关该员工所访问网站的完整列表。虽然提取一天的日志文件就已经不容易了,但 HR 人员却希望追溯到前几个星期,我可不想手动做这项工作。

公司的动态主机配置协议 (DHCP) 服务器指明数月来该员工的计算机一直都在使用相同的 IP 地址(我们在本例中假设是 192.168.17.54)。当然,这并没有什么异常,因为这是一部台式计算机,很少会关闭。但由于防火墙日志保留了源 IP 地址的记录,因此我意识到 Windows PowerShell 可能会有所帮助。

常被忽略的 Select-String 命令是其中的要点。您还将需要具备正则表达式的应用知识(我在 2007 年 11 月刊的 Windows PowerShell 中介绍了这些知识)。

Select-String 命令允许查找完全是文本文件的文件路径、正则表达式或简单字符串。然后它将输出匹配正则表达式或简单字符串的各个日志文件中的每一行。开始我只想获取包含该员工的台式计算机 IP 地址的所有行。每个日志文件行都含有一个日期和时间戳,这正是人力资源人员所寻找的全部内容。

该命令如下所示:

select-string -path c:\logs\*.txt -pattern "192.168.17.54" 
-allmatches –simplematch

–simpleMatch 参数指定我提供的模式只是一个简单字符串,而非正则表达式。图 1 显示了一部分输出,它也可以输送到文件中。请切记,该输出包含发现匹配项的文件名和行号,如果您想要返回某些时间点并发掘更多信息,这会非常有用。

本月 Cmdlet:Start-Sleep

下面的 cmdlet 可以让您在漫长的工作日中小憩一下。也就是说,Start-Sleep 让您的 Windows PowerShell 脚本有短暂的休息。

脚本需要快速暂停并不稀罕。例如,假设您需要启动一项服务,等待数秒钟后该服务启动并运行,然后执行其他一些依赖于该服务的任务。Start-Sleep 正适合上述情况。例如,运行 Start-Sleep 10 将使外壳暂停 10 秒钟。如果您需要更精确的控制,可以运行 Start-Sleep -milli 100 暂停 100 毫秒。Start-Sleep 会将外壳(包括脚本、管道和其他所有内容)按指定的时间量完全挂起。现在只要某个人编写我所需的 Start-Nap cmdlet 就行了。

fig01.gif

图 1 Select-String 命令的输出(单击图像可查看大图)

复杂的匹配项

在我向 HR 人员提供完全符合他们要求的内容之后,他们发现这仍然不是他们所需的。我的报告包含对大量 IP 地址(如 207.68.172.246(MSN® 网站))的访问。接下来,调查人员请我将报告削减为仅包含对特定 IP 地址(他们认为有问题的某一网站)的访问。在本专栏中,我不会透露调查中出现的实际 IP 地址。我将在本示例中使用 207.68.172.246(尽管 MSN 网站通常不会被视为不适宜)。

这一请求的难度稍大了一些。在我使用的日志文件中,源和目标 IP 地址恰好彼此相邻并由逗号分隔。因此我只需将我的搜索字符串更改为 "192.168.17.54,207.68.172.246" 并重复搜索。

但在更为复杂的日志文件中,两个 IP 地址之间可能存储有变量数据,这样简单的字符串匹配将不会起作用。在这种情况下,您必须采取正则表达式,对于较简单的日志格式它仍能正常工作,我将在此给出演示。

在正则表达式内,句点字符是适用于任何单个字符的通配符。我可以使用子表达式 (.)* 在我的两个 IP 地址之间搜索任意数量的字符。但是,我有必要使用反斜杠转译 IP 地址本身带有的文字句点。

产生的命令是:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" –allmatches

我删除了 –simpleMatch 参数,因为这一次我使用的是正则表达式。得到的输出仅显示特定员工的计算机对视为不适宜特定网站的访问。输出还包含调查人员所需的日期和时间戳信息。图 2 显示当您运行此类命令时可能得到的部分输出。

fig02.gif

图 2 仅显示对特定网站访问的精简搜索结果(单击图像可查看大图)

我还能将输出输送到 Format-Table 并使用其显示计算列的功能。我可以在表中加入日志文件的文件名以及发现匹配项的行号,甚至可以显示匹配行本身。但是,我可以让外壳用空字符串替换正则表达式匹配项,这样将仅显示此行的其余内容(在本例中为日期和时间戳)。这是一项高级技巧,它进一步显示了 Windows PowerShell 如何处理字符串数据并生成高度自定义的输出,全部都是在一个命令行中完成的:

select-string -path c:\logs\*.txt -pattern 
"192\.168\.17\.54(.)*207\.68\.172\.246" -allmatches | 
ft  filename,linenumber,@{"Label"="Time";
"Expression"={$_.line.replace
($_.matches[0],"")}} –auto

图 3 显示了最终结果的可能形式。

fig03.gif

图 3 Select-String 命令的格式化输出(单击图像可查看大图)

这是一个包含字符串的世界

我即将宣布 Windows PowerShell 的面向对象特性是其最大的功效之一。但有些时候选择的目标并不是对象。

Windows PowerShell 可以在面向对象的领域中发挥作用。值得庆幸的是,Windows PowerShell 团队认识到了您处理的格式化字符串经常会包含一些外部数据,因此他们加入了 Select-String 命令。有了它和正则表达式的帮助,您便可以使用 Windows PowerShell 来编写单行指令,用它解析最复杂的字符串。

Don Jones 参与编写了*《Windows PowerShell:TFM》*,而且是其他许多 IT 书籍的作者。可通过其博客 www.concentratedtech.com 与其联系。