我正在尝试在PowerShell
中编写一个接受管道输入的函数。我想使用Write-Progress
显示一个进度条,该增量用于管道中的每个项目。
例如:
function Write-PipelineProgress {
[Cmdletbinding()]
Param
(
[Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] `
[object[]] $Input,
[string] $Activity = "Processing items"
)
Begin { Write-Progress -Activity $Activity -Status "Preparing" }
Process {
# how do i determine how much progress we've made?
$percentComplete = ... ?
Write-Progress -Activity $Activity -Status "Working" -PercentComplete $percentComplete
# return current item, so processing can continue
$_
}
End { Write-Progress -Activity $Activity -Status "End" -Completed }
}
Get-ChildItem | Write-PipelineProgress -Activity "Listing files"
如何确定进度(完成百分比)?
答案 0 :(得分:6)
您需要知道管道中的项目数以跟踪进度。
如果管道参数被正确声明,那么Powershell 3.0可以让您计算管道中的内容,而不必在访问.Count
$Input
属性之外做任何工作。这也意味着您可以取消begin {} process {} end {}
块,只需要一个简单的功能。
早期版本没有Count
属性,因此您首先必须迭代并捕获管道以获取计数然后再次处理,这不是那么有效,我将在稍后展示。
Powershell V2版本:
function Show-ProgressV2{
param (
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[PSObject[]]$InputObject,
[string]$Activity = "Processing items"
)
Begin {$PipeArray = @()}
Process {$PipeArray+=$InputObject}
End {
[int]$TotItems = ($PipeArray).Count
[int]$Count = 0
$PipeArray|foreach {
$_
$Count++
[int]$percentComplete = [int](($Count/$TotItems* 100))
Write-Progress -Activity "$Activity" -PercentComplete "$percentComplete" -Status ("Working - " + $percentComplete + "%")
}
}
}
Powershell V3版本:
function Show-ProgressV3{
[CmdletBinding()]
param (
[Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true)]
[PSObject[]]$InputObject,
[string]$Activity = "Processing items"
)
[int]$TotItems = $Input.Count
[int]$Count = 0
$Input|foreach {
$_
$Count++
[int]$percentComplete = ($Count/$TotItems* 100)
Write-Progress -Activity $Activity -PercentComplete $percentComplete -Status ("Working - " + $percentComplete + "%")
}
}
<强>效率强>
比较两者,V3功能大约快5-6倍,具体取决于管道的大小。
考虑以下预过滤文件列表,查找我家驱动器中的所有.jpg
文件,根据您的评论选择前200个文件以及排序和列表,在管道中使用该功能3次: / p>
$V2 = Measure-Command {Get-ChildItem -Filter *.jpg -Recurse `
| Show-ProgressV2 -Activity "Selecting" `
| Select-Object -First 200 `
| Show-ProgressV2 -Activity "Sorting" `
| Sort-Object -Property FullName `
| Show-ProgressV2 -Activity "Listing" `
| FL}
$V3 = Measure-Command {Get-ChildItem -filter *.jpg -Recurse `
| Show-ProgressV3 -Activity "Selecting" `
| Select-Object -First 200 `
| Show-ProgressV3 -Activity "Sorting" `
| Sort-Object -Property FullName `
| Show-ProgressV3 -Activity "Listing" `
| FL}
$V2
$V3
这给了我以下时间:
PS C:\Users\Graham> C:\Users\Graham\Documents\Stack_ShowProgress_Pipeline.ps1
Days : 0
Hours : 0
Minutes : 0
Seconds : 48
Milliseconds : 360
Ticks : 483607111
TotalDays : 0.000559730452546296
TotalHours : 0.0134335308611111
TotalMinutes : 0.806011851666667
TotalSeconds : 48.3607111
TotalMilliseconds : 48360.7111
Days : 0
Hours : 0
Minutes : 0
Seconds : 8
Milliseconds : 335
Ticks : 83358374
TotalDays : 9.6479599537037E-05
TotalHours : 0.00231551038888889
TotalMinutes : 0.138930623333333
TotalSeconds : 8.3358374
TotalMilliseconds : 8335.8374
答案 1 :(得分:1)
您必须决定如何显示进度。在这个例子中,我随意决定开始块占5%,过程块占用90%,结束块占5%。从那里,您可以以任意方式显示中间百分比(例如,在开始块中从0%到5%)(这是此示例在开始和结束块中执行的操作)。或者,您可以根据脚本实际执行的处理量(这是进程块的作用)来确定百分比。请注意,此示例或多或少是无意义的(但它将执行并显示进度条。)。另请注意,编写的脚本在管道中不起作用,因此开始/进程/结束块不是必需的,但它们不会受到伤害。
function progress-example {
param( [string[]] $files)
begin {
# This code is somewhat arbitrarily considering the begin block to
# take 5% of the time of this cmdlet. The process block is
# considered to take 90% of the time, and the end block the last 5%
write-progress -Activity "Progress Example" -status Beginning `
-CurrentOperation "Initializing sorted script table" -PercentComplete 0
# This could be any kind of initialization code;
# The code here is non-sense
$mySortedScriptTable = @{}
ls *.ps1 | % { $mySortedScriptTable[$_.name] = cat $_ | sort }
sleep 2 # this code executes too quickly to see the progress bar so slow it down
write-progress -Activity "Progress Example" -status Beginning `
-CurrentOperation "Initializing script size table" -PercentComplete 3
$mySortedScriptSizeTable = @{}
ls *.ps1 | % { $mySortedScriptSizeTable[$_.name] = $_.Length }
$totalSizeRequested = 0
foreach ($file in $files) {
$totalSizeRequested += $mySortedScriptSizeTable[$file]
}
$numberCharsProcessed = 0
sleep 2 # this code executes too quickly to see the progress bar so slow it down
write-progress -Activity "Progress Example" -status Beginning `
-CurrentOperation "Initialization complete" -PercentComplete 5
sleep 2 # this code executes too quickly to see the progress bar so slow it down
}
process {
foreach ($file in $files) {
$thisFileSize = $mySortedScriptSizeTable[$file]
# Process block takes 90% of the time to complete (90% is arbitrary)
$percentProcess = 90 * ($numberCharsProcessed / $totalSizeRequested)
write-progress -Activity "Progress Example" -status "Processing requested files" `
-CurrentOperation "Starting $file" -PercentComplete (5 + $percentProcess)
"File $file requested. Size = $thisFileSize. Sorted content follows"
$mySortedScriptTable[$file]
$numberCharsProcessed += $thisFileSize
$percentProcess = 90 * ($numberCharsProcessed / $totalSizeRequested)
write-progress -Activity "Progress Example" -status "Processing requested files" `
-CurrentOperation "Starting sleep after $file" -PercentComplete (5 + $percentProcess)
sleep 2 # slow it down for purposes of demo
}
}
end {
write-progress -Activity "Progress Example" -status "Final processing" `
-CurrentOperation "Calculating the fun we had with this example" -PercentComplete (95)
sleep 2
write-progress -Activity "Progress Example" -status "Final processing" `
-CurrentOperation "It's looking like we had mucho fun" -PercentComplete (97)
sleep 2
write-progress -Activity "Progress Example" -status "Final processing" `
-CurrentOperation "Yes, a lot of fun was had" -PercentComplete (99)
sleep 1
}
}
progress script1.ps1, script2.ps1, script3.ps1
答案 2 :(得分:1)
我发布了Write-ProgressEx cmdlet以避免例行代码。试试吧。
项目https://github.com/mazzy-ax/Write-ProgressEx
我想使用Write-Progress显示进度条,该进度条为管道中的每个项目增加。
使用Write-ProgressEx开关 - 增量。
cmdLet商店Total
和Current
。它会自动计算PercentComplete
和SecondsRemaining
。
如何确定进度(完成百分比)?
如果开发人员提供Total
和Current
,则会自动执行cmdlet Write-ProgressEx calcaulte -PercentComplete。如果指定了switch -Increment,则cmdlet增量Current
。
开发人员可以使用Get-ProgressEx获取参数的实际值。
参见示例https://github.com/mazzy-ax/Write-ProgressEx/tree/master/samples
<小时/> 更多详情:
Write-ProgressEx扩展了标准PowerShell cmdlet的功能。它提供了一种使用-PercentComplete和-SecondsRemaining开关的简单方法。
cmdlet:
注意:使用多线程时,cmdlet不安全。