2

我似乎遇到了一个奇怪的错误,或者我的脚本中遗漏了一些东西。

在我的脚本中,我使用人造进度条功能显示进度。它通过重复更新控制台的同一行来工作,模仿进度条。请看下面的函数:

# Update-Progress-Bar : v1.0 : 2013-07-29
# Displays a percentage bar. Meant to be used repeatedly to update the same console line (giving the appearance of incrementing progress).
# - $Percentage : Determines how much progress is shown on the bar.
# - $Message : The message that accompanies the progress bar.
function Update-Progress-Bar ($Percentage, $Message){
    # Save the current cursor position so we can come back later.
    $CursorPosition = $Host.UI.RawUI.CursorPosition

    # Convert the percentage into a proper progress bar.
    $ProgressBarMax = "20"
    $ProgressBarCount = [Math]::Floor([Decimal]($Percentage / 5))
    $ProgressBar = ("#" * $ProgressBarCount) + (" " * ($ProgressBarMax - $ProgressBarCount))

    # Change the format of the percentage depending on length.
    switch ($Percentage.Length){
        1 {$Percentage = "  " + $Percentage + "%"}
        2 {$Percentage = " " + $Percentage + "%"}
        default {$Percentage = $Percentage + "%"}
    }

    # Trim or pad the message as necessary.
    $MessageMaxLength = "50"
    if ($Message.Length -gt $MessageMaxLength){ $Message = $Message.Remove($MessageMaxLength) }
    else { $Message = $Message + (" " * ($MessageMaxLength - $Message.Length)) }    

    # Display our progress bar, percentage, and message.
    Write-Host -nonewline -ForeGroundColor Blue "[$ProgressBar] $Percentage"
    Write-Host " | $Message"

    # Revert back to the original cursor position.
    $Host.UI.RawUI.CursorPosition = $CursorPosition
}

无论出于何种原因,在处理了大约 100 多条记录之后(我将其用作脚本的一部分,我定期对 1000 台机器执行操作),它开始执行双换行符,这破坏了进度条的功能. 所以我最终得到了这个......

[ 126 / 2275 ] ComputerName1
[                    ]   0% | Verifying network connectivity...

[##                  ]  10% | Verifying file system access...

[####                ]  20% | Determining installed operating system...

[######              ]  30% | Executing action...

[####################] 100% | Action Completed



[ 127 / 2275 ] ComputerName2
[                    ]   0% | Verifying network connectivity...

[##                  ]  10% | Verifying file system access...

[####                ]  20% | Determining installed operating system...

[######              ]  30% | Executing action...

[####################] 100% | Action Completed

当我应该有....

[ 126 / 2275 ] ComputerName1
[####################] 100% | Action Completed

[ 127 / 2275 ] ComputerName2
[####################] 100% | Action Completed

关于这个问题的任何想法和可能的解决方法?

编辑#1:当我达到控制台的缓冲区高度限制时,是否可能发生这种情况(如,它开始丢弃旧的输出行)?

编辑#2:我已经确认如果我增加控制台窗口的缓冲区宽度和高度,这个问题就会消失。我仍然不确定如何解决这个错误。想法?

4

1 回答 1

0

我在自己的机器上验证了这个错误。一旦你开始包装缓冲区, -nonewline 就无法完成它的任务。

您可以做一些事情作为解决方法:

1) 以编程方式将 BufferSize 增加到固定大小

$Host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size(120, 5000)

2)每隔一段时间清除一次屏幕,也许每100个节点或每个节点之后,如果您不需要关注输出

3) 仅在接近缓冲区限制时才清屏

if($Host.UI.RawUI.CursorPosition.Y -gt ($Host.UI.RawUI.BufferSize.Height - 5)) {cls}

4) 通过暂时减小缓冲区的大小,仅清除屏幕缓冲区的旧部分。我使用了您的功能,未动过(重命名以删除第二个“-”除外)。屏幕缓冲区为 100 时,奇怪的行为将从第 50 号开始(每个循环 2 行输出)

49 / 2000
[####################] 100% | FINAL
50 / 2000
[####                ]  20% | First
[########            ]  40% | Second
[############        ]  60% | Third
[################    ]  80% | Fourth
[####################] 100% | FINAL

51 / 2000
[####                ]  20% | First
[########            ]  40% | Second
[############        ]  60% | Third
[################    ]  80% | Fourth
[####################] 100% | FINAL

但是通过 BufferSize 切换,我一路顺利地达到了 2000/2000

1998 / 2000
[####################] 100% | FINAL
1999 / 2000
[####################] 100% | FINAL
2000 / 2000
[####################] 100% | FINAL

$range = 1..2000

测试代码如下:

foreach($i in $range)
{
    $Host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size(120, 3000)

    Write-Host
    Write-Host $i "/ 2000"

    Update-ProgressBar "20" "First"
    Update-ProgressBar "40" "Second"
    Update-ProgressBar "60" "Third"
    Update-ProgressBar "80" "Fourth"
    Update-ProgressBar "100" "FINAL"

    $Host.UI.RawUI.BufferSize = New-Object System.Management.Automation.Host.Size(120, 2990)
}

实际上,您可以将 3 和 4 结合起来,以便仅在缓冲区快满时才清除缓冲区的旧部分。

于 2013-08-29T16:35:00.110 回答