在循环期间显示进展

时间:2017-05-03 23:49:50

标签: loops powershell progress

我有一个想要显示进度的ForEach循环:

1..254 | ForEach-Object {Test-Connection -ErrorAction SilentlyContinue -count 
1 -TimeToLive 32 "$ipcut.$_"}
#^need to get a progress bar somewhere here^

我已尝试在上面的代码中的各个地方使用write-progress,并且似乎无法使其工作,因为它从1-254循环。

3 个答案:

答案 0 :(得分:5)

这样的东西?

$ipCut ='192.168.1'    ### not included in the original question

$arrTest = 1..254
$all = $arrTest.Count
$i = 0
$arrTest | ForEach-Object {
   Write-Progress -PercentComplete (
       $i*100/$all) -Activity "PINGs completed: $i/$all"  -Status 'Working'
   Test-Connection -ErrorAction SilentlyContinue -count 1 -TimeToLive 32 "$ipcut.$_"
   $i++
}

参考:Write-Progress cmdlet

  

Write-Progress cmdlet在Windows中显示进度条   PowerShell命令窗口,描述正在运行的命令的状态   或脚本。您可以选择栏反映的指标和   显示在进度条上方和下方的文本。

编辑:将代码重写为单行代码很简单:只需用分号(;)分隔特定命令,而不是换行符:

$arr=1..254; $all=$arr.Count; $i=0; $arr|ForEach-Object{Write-Progress -PercentComplete ($i*100/$all) -Activity "PINGs completed: $i/$all"  -Status 'Working'; Test-Connection -ErrorAction SilentlyContinue -count 1 -TimeToLive 32 "$ipcut.$_"; $i++}
分别使用硬编码1..254254代替$arr$all更简单:

$i=0; 1..254|ForEach-Object{Write-Progress -PercentComplete ($i*100/254) -Activity "PINGs completed: $i/254"  -Status 'Working'; Test-Connection -ErrorAction SilentlyContinue -count 1 -TimeToLive 32 "$ipcut.$_"; $i++}

答案 1 :(得分:3)

Josef Z.'s helpful answer向您展示了一个可行的解决方案。

仅仅通过在现有命令的Write-Progress脚本块中插入ForEach-Object命令来获取进度条的特定愿望是不可能的,但是:

传递给ForEach-Object的脚本块无法事先知道 将通过管道传递多少个对象,这是显示的先决条件百分比方面的进展。

必须确定提前的迭代次数。

如果你想概括一下,请使用功能 ,例如以下内容(故意保持简单):

function Invoke-WithProgress {
  param(
    [scriptblock] $Process,
    [string]      $Activity = 'Processing'
  )
  # Collect the pipeline input ($Input) up front in an array list.
  $al = New-Object System.Collections.ArrayList 100  # 100 is the initial capacity 
  foreach ($o in $Input) { $null = $al.Add($o) }
  # Count the number of input objects.
  $count = $al.Count; $i = 0
  # Process the input objects one by one, with progress display.
  $al | ForEach-Object {
    Write-Progress -PercentComplete ((++$i)*100/$count) -Activity "$Activity $i/$count..."
    . $Process
  }
}

再次注意,所有管道输入都是预先收集

在您的情况下,您将按如下方式调用它:

1..254 | Invoke-WithProgress {
 Test-Connection -ErrorAction SilentlyContinue -count 1 -TimeToLive 32 "$ipcut.$_"
}

答案 2 :(得分:1)

您无法真正添加进度条并将代码保留为单个语句,但您可以通过分号分隔所需的命令来在一行中执行此操作:

1..254 | ForEach-Object -Begin {$i = 0} -Process {Write-Progress -PercentComplete ($i/254*100) -Activity "Tests completed: $i/254" -Status "Testing $ipcut.$_"; Test-Connection -ErrorAction SilentlyContinue -count 1 -TimeToLive 32 "$ipcut.$_"; $i++}

这使用ForEach-Object命令中的-Begin块将计数器$i初始化为0.根据评论,使用这种方法我们必须对集合的总数进行硬编码,因为那里&#39 ;无法从ForEach-Object循环中以编程方式确定它,因为每次迭代都会处理集合中的单个项目。这主要是有问题的,因为你在一个数字范围内管道,就像你在一个集合中管道一样,我们可以使用该集合的.count属性来确定总数。

但是,值得注意的是,您 您可以使用它向用户显示一条消息(没有移动进度条),该消息至少仍然可以显示进度(而不是您的总工作量)。这样做可以简化代码:

Write-Progress