ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、视频、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
## 24.4 通过Select-String使用正则表达式 现在我们终于到了本章的精华之处。我们使用一些IIS日志文件作为示例,这是由于IIS日志是纯文本,而这正是正则表达式的用武之地。如果能将这些日志以更面向对象的风格读取到PowerShell中,那再好不过。可惜不能……所以只能使用正则表达式。 让我们先在日志文件中查找40x错误。这类错误主要是“找不到文件”以及其他错误,我们希望为Web开发人员生成一个缺失文件的报表。日志文件中,每一个HTTP请求为一行,每行又被分为以空格分割的域。我们还有一些文件名称中包含“401”等,比如“error401.html”,我们不希望这部分结果出现在我们的结果中。我们将会指定一个类似`\s40[0-9]\s`的正则表达式,因为通过在40x错误之前和之后匹配空格,该表达式将能够匹配从400到499的错误。下面是我们使用的命令。 ``` <pre class="dai_ma_wu_xing_hao">``` PS C:\logfiles> get-childitem -filter *.log -recurse | select-string -pattern "\s40[0-9]\s" | format-table Filename,LineNumber,Line –wrap ``` ``` 注意,我们将当前目录变更为C:\\logfiles,开始运行命令。我们通过寻找所有以.log结尾的文件,并递归查找子目录。这可以确保所有的日志文件都可以被包含在输出结果之内。接下来我们使用`Select-String`,提供正则表达式作为参数。该命令的结果是一个类型为MatchInfo的对象;这里使用`Format-Table`命令,使得显示结果包含文件名称、行号以及包含匹配结果的文本。这使得找到缺失文件非常容易。然后我们将报表给予Web开发人员。 接下来,我们希望扫描所有被基于Gecko浏览器访问过的文件。开发人员告诉我们,使用该类浏览器访问我们的网站的用户会遇到一些问题,他们希望找到具体被访问的文件。他们还希望将问题范围缩减为使用Windows NT6.2操作系统运行浏览器的用户,这意味着我们需要在`user-agnet`中寻找类似下面的字符串。 ``` <pre class="dai_ma_wu_xing_hao">``` (Windows+NT+6.2;+WOW64;+rv:11.0)+Gecko ``` ``` 开发人员强调是否为64位操作系统无关紧要,因此我们不希望`U``ser-agent`中仅是包含“WOW64”的结果。最终我们得到这个正则表达式:`6\.2;[\w\W]+\+Gecko`—— 让我们对其进行分解。 - `6\.2;`——这就是“6.2”;我们使用转义字符将句号变为字面意思上的句号,而不是作为单字符的通配符。 - `[\w\W]+` ——一个或多个字符或非字符——换句话说是任何内容。 - `\+Gecko` ——也就是字面意义上的加号,然后是“Gecko”。 下面是从日志文件返回匹配行的命令,还包含前几行的返回结果。 ``` <pre class="dai_ma_wu_xing_hao">``` PS C:\logfiles> get-childitem -filter *.log -recurse | ➥select-string -pattern "6\.2;[\w\W]+\+Gecko" W3SVC1\u_ex120420.log:14:2012-04-20 21:45:04 10.211.55.30 GET /MyApp1/Testpage.asp - 80 - 10.211.55.29 Mozilla/5.0+(Windows+NT+6.2;+WOW64;+rv:11.0)+Gecko/20100101+Firefox/11.0 200 0 0 1125 W3SVC1\u_ex120420.log:15:2012-04-20 21:45:04 10.211.55.30 GET /TestPage.asp- 80 - 10.211.55.29 Mozilla/5.0+(Windows+NT+6.2;+WOW64;+rv:11.0)+Gecko/20100101+Firefox/11.0 200 0 0 1 109 ``` ``` 这次我们保持输出结果为默认格式,而不是将结果发送给用于格式化的Cmdlet。 在最后一个例子中,将IIS日志文件变为Windows安全日志。事件日志实体中包含`Message`属性,该属性中包含关于事件信息的细节。遗憾的是,该信息并没有良好的格式化以便于人们阅读,也不易于计算机解析。我们希望查找所有事件ID为4624的事件,该事件代表账户登录事件(该ID代表的含义可能根据Windows版本的不同而有所不同;我们的示例是在Windows Server 2008 R2上)。但我们只希望查看账户名称以“WIN”开头的登录信息,这些账户都与在域中的计算机账户关联。另外,我们还要求账户结尾必须是从`TM20$`到`TM40$`的字符,这些是我们感兴趣的特定计算机。我们需要的正则表达式大概如下:`WIN[\W\w]+TM[234][0-9]\$` ——注意我们需要使用转义符号将末尾的`$`进行转义,因此该符号不会被解释成字符串结尾标记。我们需要包含`[\W\w]`(非字符和字符),这是由于我们的账户名称中可能包含连字符,该连字符无法与`\w`字符类匹配。因此最终下面是我们的命令。 ``` <pre class="dai_ma_wu_xing_hao">``` PS C:\> get-eventlog -LogName security | where { $_.eventid -eq 4624 } | ➥select -ExpandProperty message | select-string -pattern ➥"WIN[\W\w]+TM[234][0-9]\$" ``` ``` 在开始部分,我们使用`Where-Object`,从而仅使得ID为4624的事件被筛选出来。然后我们将`Message`属性的内容存入纯字符串,并通过管道将其传输给`Select-String`。注意,这将会输出匹配的信息文本;如果我们的目标是输出所有匹配的事件,我们需要使用另一种方式。 ``` <pre class="dai_ma_wu_xing_hao">``` PS C:\> get-eventlog -LogName security | where { $_.eventid -eq 4624 -and ➥$_.message -match "WIN[\W\w]+TM[234][0-9]\$" } ``` ``` 这里,我们不是输出`Message`属性的内容,而是查找`Message`属性匹配正则表达式的记录——接下来输出整个Event对象。接下来所使用的命令取决于结果希望输出的形式。