Powershell 将Progressbar添加到现有脚本

Powershell 将Progressbar添加到现有脚本,powershell,progress-bar,Powershell,Progress Bar,我得到了一个脚本来过滤SMTP日志文件,它分为两部分第一部分 $result = Get-Content (path) | ForEach-Object { if($_ -match '(\d{2}\.\d{2}\.\d{4} \d{2}:\d{2}:\d{2}).*\(((?:\d{1,3}\.){3}\d{1,3})\) disconnected\.?\s+(\d+) message\[s\]'){ try { $dns = [System.N

我得到了一个脚本来过滤SMTP日志文件,它分为两部分第一部分

$result = Get-Content (path) | ForEach-Object {
    if($_ -match '(\d{2}\.\d{2}\.\d{4} \d{2}:\d{2}:\d{2}).*\(((?:\d{1,3}\.){3}\d{1,3})\) disconnected\.?\s+(\d+) message\[s\]'){
        try {
            $dns = [System.Net.Dns]::GetHostEntry($matches[2]).HostName
        }
        catch { 
            $dns = 'Not available' 
        }
        [PsCustomObject]@{
            IP       = $matches[2]
            Messages = [int]$matches[3]
            DNSName  = $dns
            Date     = [datetime]::ParseExact($matches[1], 'dd.MM.yyyy HH:mm:ss', $null)
        }
    }
}
过滤我需要的所有信息,例如IP、传入消息编号、DnsName。第二个

$cumulative = $result | Group-Object -Property IP | ForEach-Object {
    [PsCustomObject]@{
        IP = $_.Name
        Messages = ($_.Group | Measure-Object -Property Messages -Sum).Sum
        DNSName = $_.Group[0].DNSName
        Date    = ($_.Group | Sort-Object Date)[-1].Date
    }
}
仅统计每个IP的传入消息,并仅显示最近的日期


现在我想添加一个Progressbar,因为我不确定是否可以将它们合并到一个命令中,我可能会尝试在两个命令中都添加一个Progressbar。我读过关于Write progress命令的文章,但我不知道如何将其包含到现有的代码中。

事实上,您可以将这两个命令组合起来。在解析日志文件的行时,我们将使用
$cumulative
进行分组
$cumulative
是一个
[哈希表]
,因此我们可以通过IP聚合数据,并对动态消息的数量求和。这意味着更少的操作,从而提高性能

对于进度条,
Write progress
是一个适当的选择。要在这里使用它,我们必须快速估计日志文件的行数我们不应该在开始时读取日志文件内容来计算行数,因为这将增加一个耗时的大量I/O操作,其唯一目的是显示进度条。为了避免这种情况,我们将根据文件大小(以字节为单位)除以估计的行平均长度来假设它的行数。得到文件大小,做这个数学运算真的很快,所以我们可以负担进度条的费用。有了这个估计的行数,我们就可以在解析文件的同时更新进度条,以非常低的时间成本。在这样做的同时,我们可以调整估计的行长度,以便为我们阅读的每一行获得更准确的进度计算

下面是相应的脚本,它将两个操作与全局进度条相结合:

$lfile="path"
$cumulative=@{};
# We need the file size for progress bar
$loginfo=Get-item -Path $lfile
if (!$loginfo) {
  Write-Host ("Can't find log file... : "+$lfile)
  exit 1;
}
# We'll keep a estimated line length average and the corresponding estimated number of lines of the file
# We could have started with a fixed average, but let's estimate it while rading the file
$estimateaveragelinelength=0 
$estimatelinenumber=1
$totallinelength=0 
# Counters to update the progress bar
$percent=0
$curline=0
Write-Progress -Activity ("Parsing log file "+$lfile) -Status "Start" -Id 1 -PercentComplete 0
$result = Get-Content ($lfile) | ForEach-Object {
    if($_ -match '(\d{2}\.\d{2}\.\d{4} \d{2}:\d{2}:\d{2}).*\(((?:\d{1,3}\.){3}\d{1,3})\) disconnected\.?\s+(\d+) message\[s\]'){
        try {
            $dns = [System.Net.Dns]::GetHostEntry($matches[2]).HostName
        }
        catch { 
            $dns = 'Not available' 
        }
        # We store the object we'll add to $result.
        # If you have no more usage of $result after, you should remove $result.
        $msg=[PsCustomObject]@{
            IP       = $matches[2]
            Messages = [int]$matches[3]
            DNSName  = $dns
            Date     = [datetime]::ParseExact($matches[1], 'dd.MM.yyyy HH:mm:ss', $null)
        }
        # We do the grouping on the fly by IP, summing the number of messages
        # and keeping only the most recent date by IP
        if (!$cumulative.ContainsKey($msg.IP)) {
          $cumulative.Add($msg.IP, [PsCustomObject]@{
            IP = $msg.IP
            Messages = $msg.Messages
            DNSName = $dns
            Date    = $msg.Date
          })
        } else {
          $cumulative[$msg.IP].Messages+=$msg.Messages;
          if ($cumulative[$msg.IP].Date -lt $msg.Date) {
            $cumulative[$msg.IP].Date = $msg.Date;
          }
        }
        $msg
    }
    # Count number of lines currently read
    $curline++;
    # Adjust the estimated average line length from current line 
    # and then the corresponding estimated number of lines of the file
    if ($estimateaveragelinelength -eq 0) {
      # First read, we start with the first line length
      $estimateaveragelinelength = $_.Length
      $totallinelength = $_.Length
    } else {
      $totallinelength += $_.Length
      # Adjust the average length with the current line Length
      $estimateaveragelinelength = [math]::round($totallinelength / $curline)
    }
    # We'll ignore empty lines
    if ($estimateaveragelinelength -ne 0) {
      # Adjust the corresponding estimated number of lines of the file with the actual average line length
      # As $totallinelength  can't be greater than $loginfo.Length, we should never excess 100%, 
      # thus $estimatelinenumber can't be greater than the real number of  the lines
      $estimatelinenumber=[math]::round(($loginfo.Length / $estimateaveragelinelength))
      # Do the math and update progress bar
      $curpercent=[math]::round(($curline/$estimatelinenumber)*100);
      if ($curpercent -ne $percent) {
        $percent=$curpercent
        Write-Progress -Activity ("Parsing log file "+$lfile) -Status "In progress" -Id 1 -PercentComplete $curpercent
      }
    }
}
Write-Progress -Activity ("Parsing log file "+$lfile) -Status "Done" -Id 1 -PercentComplete 100 -Completed
$cumulative

嘿,这看起来很好,但我不能让它正常工作。Powershell告诉我在第18行中,第19行缺少“”(“”或“”)”,但我找不到缺少的位置,他还说{在第18行的ForEach对象丢失之后。@Trippin修复了丢失的
-match
,我的错误,复制和粘贴失败。非常感谢。输出格式与初始命令不同,因为它现在是hashtabell而不是PSCustomObject吗?@Trippin是的,它现在返回
[PSCustomObject]的
[Hashtable]
由IP索引,而不是
[PSCustomObject[]]
(PSCustomObject的数组)。如果需要数组,可以使用数组强制转换为
$cumulative
值,如
[PSCustomObject[]]$cumulative.values
,该数组将返回
[PSCustomObject[]]