使用select-String解析日志文件

时间:2018-11-10 09:47:39

标签: powershell

团队, 预先感谢,我是ITPro,正在学习PowerShell。我有一个日志文件,其中包含以下格式的数据。我已经附上了图片。 我在其中找到所有已完成传输的行,然后运行-each循环使用-eq运算符查找日期与当前日期匹配的行

然后我想从运行foreach循环的当前行中获取特定的文件名。我的示例示例:日志中第一条完成的传输线与当前日期匹配,因此我想获取文件名HardwareEvents.evtx。

但是我找不到任何方法可以帮助我在当前运行的每一行中解析文件名。

如果获得文件名,则可以使用powersell cmdlet删除文件。

        $var = Select-String -Path "C:\Creds\AzCopyVerbose.log" -Pattern 'Finished Transfer' | `
Select-Object -Last 20 | ForEach-Object `
    {
      if (($_.Line).Substring(1,10) -eq (Get-Date).ToString('yyyy/MM/dd'))
      {
        $_.Line. // There is no method which I'm aware of need help in this if statement
      }
      Else {Write-Host "The date present in the azcopy verbose log is older"}
    }

enter image description here

3 个答案:

答案 0 :(得分:1)

要从日期为今天的日志中获取文件名,可以使用以下方法:

$logfile = 'C:\Creds\AzCopyVerbose.log'
$today = Get-Date -UFormat "%Y/%m/%d"
$pattern = '^\[(?<date>\d{4}/\d{2}/\d{2}).*Finished transfer:\s+(?<filename>.*)\s+=>.*$'
Select-String -Path $logfile -Pattern $pattern | Select-Object -Last 20 | ForEach-Object {
    $null = $_.Line -match $pattern
    if ($matches['date'] -eq $today) {
        Write-Host $matches['filename']
    }
    else {
        Write-Host "The date present in the azcopy verbose log is older"
    }
}

除了使用Select-String之外,您还可以执行此操作,该操作只需要匹配一次模式,因此我认为更简洁一些:

$logfile = 'C:\Creds\AzCopyVerbose.log'
$today = Get-Date -UFormat "%Y/%m/%d"
$pattern = '^\[(?<date>\d{4}/\d{2}/\d{2}).*Finished transfer:\s+(?<filename>.*)\s+=>.*$'
Get-Content -Path $logfile | Select-Object -Last 20 | Where-Object { $_ -match $pattern } | ForEach-Object {
    if ($matches['date'] -eq $today) {
        Write-Host $matches['filename']
    }
    else {
        Write-Host "The date present in the azcopy verbose log is older"
    }
}

p.s。我使用Get-Date -UFormat "%Y/%m/%d"是因为荷兰计算机上的(Get-Date).ToString('yyyy/MM/dd')输出2018-11-10

正则表达式详细信息

^                     Assert position at the beginning of the string
\[                    Match the character “[” literally
(?<date>              Match the regular expression below and capture its match into backreference with name “date”
   \d                 Match a single digit 0..9
      {4}             Exactly 4 times
   \/                 Match the character “/” literally
   \d                 Match a single digit 0..9
      {2}             Exactly 2 times
   \/                 Match the character “/” literally
   \d                 Match a single digit 0..9
      {2}             Exactly 2 times
)
.                     Match any single character that is not a line break character
   *                  Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
Finished\ transfer:   Match the characters “Finished transfer:” literally
\s                    Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   +                  Between one and unlimited times, as many times as possible, giving back as needed (greedy)
(?<filename>          Match the regular expression below and capture its match into backreference with name “filename”
   .                  Match any single character that is not a line break character
      *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s                    Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   +                  Between one and unlimited times, as many times as possible, giving back as needed (greedy)
=>                    Match the characters “=>” literally
.                     Match any single character that is not a line break character
   *                  Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
$                     Assert position at the end of the string (or before the line break at the end of the string, if any)

答案 1 :(得分:1)

补充Theo's helpful answer

这不是很明显,但是可以 Select-String脚本块中访问ForEach-Object命令的[命名]捕获组匹配(无需与-match重复匹配):

PS> '... File transfer: C:\path\to\file => ...' |
      Select-String '\bFile transfer: (?<file>.+?) =>' | 
        ForEach-Object { $_.Matches[0].Groups['file'].Value }
C:\path\to\file  # Value of named capture group 'file' 
  • $_.Matches是当前输入行的匹配项的集合;除非指定了-AllMatches,否则只有一个一个条目,索引为0

  • .Groups访问捕获组匹配项的集合(索引0的条目包含整体匹配项。)

  • ['file']访问命名捕获组file的匹配项,但请注意,从 index 开始,基于-em的访问(对于未命名捕获组)同样有效索引1;也就是说,上面命令中的$_.Matches[0].Groups[1].Value会产生相同的结果。

就数据类型而言,Select-String发出[Microsoft.PowerShell.Commands.MatchInfo]实例,其.Matches属性是[System.Text.RegularExpressions.Match]实例的数组。

答案 2 :(得分:0)

以下是使用正则表达式作为日期的方法。

$var = Select-String -Path "C:\Creds\AzCopyVerbose.log" -Pattern 'Finished Transfer' | 
Select-Object -Last 20 | ForEach-Object -Process {
      $_.Line -match '\d{4}/\d{2}/\d{2}' | Out-Null
      [string]$Match = $Matches.Values
      if ([Datetime]$Match -eq (Get-Date).ToString('yyyy/MM/dd'))
      {
        $_.Line. // There is no method which I'm aware of need help in this if statement
      }
      Else {Write-Host "The date present in the azcopy verbose log is older"}
    }