-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Description
Write-Progress has long been perhaps the most neglected of the standard Write-* cmdlets. The problems with it are both in terms of its user-facing and in terms of its behind-the-scenes implementation, and I'll attempt to break them up as such.
Behind-the-Scenes Problems
- There is no
Progressstream. This makes it the only defaultWrite-*cmdlet without a matching stream (barring of course the special-casedWrite-Host, which utilises the Information stream).- I believe there should be a stream, and that stream should be handled in a similar way to the Information stream in terms of the objects that pass through it (though naturally Progress displays by default, unlike Information).
- Providing a stream for this permits suppression and redirection of the progress information from specific cmdlets instead of requiring that an implementation continually override
$ProgressPreferenceand hope that it works. - The fact that it is stream-like is more confusing for users, given that it seems to respect $ProgressPreference variable values that mimic the standard stream preferences' available levels, but it cannot be redirected and there is no common parameter for handling it as with all the other stream-type Write-* cmdlets.
- The
$ProgressPreferencevariable is not handled the same as, for example,$ErrorActionPreference, or indeed most other preference variables that work with streams; it seems to be simply a variable that theWrite-Progresscmdlet looks to see is defined and acts accordingly.- Because Progress is not a stream, the only way to attempt to handle, suppress, or indeed do anything at all with the Progress data is via this variable. This makes it incredibly unwieldy, because in order to tell a command not to show a progress bar, the variable needs to be modified both before & after the command (in order to restore it to normal order).
- Combined with this, there's no way to check if the preference is being altered by the caller of the cmdlet (i.e., as you can do with
$PSBoundParameters['ErrorAction']) or if the value is simply stored in the$ProgressPreferencevariable from... really, no one knows where, for sure.
User-Facing (Usability) Problems
See this project: https://github.com/mazzy-ax/Write-ProgressEx
Write-Progress is probably the only (that I've seen...) default Write-* cmdlet that spawned an entire project to help deal with its idiosyncrasies. Write-Information has spawned a couple, to allow easier interaction with the necessary metadata that sets display colors on those objects (but that's a separate issue), but pretty much no other default stream / associated Write- cmdlet has received or needs this much coddling from the community.
We need only look at the README.MD file on the above linked repository for a fairly comprehensive summary of the present pain-points with the default Write-Progress cmdlet that the creator felt it necessary to fix.
Write-ProgressEx extends the functionality of the standard powershell cmdlet. Write-ProgressEx is a powershell native cmdlet that provides a simple way to show ProgressBars with PercentComplete and SecondsRemaining.
The cmdlet:
- works with pipe;
- works with empty activity string;
- completes all inner progresses if no parameters;
- automatically completes with pipe;
- automatically calculates percents, remaining seconds and elapsed time;
- automatically displays current iteration and totals on progress bar;
- automatically set parent id for a inner loop;
- stores totals, current values and actual parameters into the module hashtable;
- provides get/set cmdlets to access actual parameters;
- uses script blocks to show messages with date, time, iterations and elapsed time on events:
- first iteration;
- activity changed;
- status changed;
- completed.
- provides a counter functional. See Write-ProgressEx as a counter;
- uses the caller function name or the caller script file name as the Activity;
- accepts -ShowProgressBar Auto parameter to reduce the overhead for redrawing a screen. It recognizes None and Force values also.
The sheer amount of manual calculations required to use the default Write-Progress cmdlet is pretty absurd, in my opinion. We don't need to determine for ourselves the basic functional information or metadata for any default stream-writing cmdlet, really.
There is so much manual input the user is forced to almost completely create the progress bar, and all Write-Progress is doing is working out purely the display issues. This makes some sense, but it doesn't seem to make any sense to me to make it such a difficult command to work with. The current implementation of the Write-Progress cmdlet seems more apropos for an internal utility command to support a fully-fledged Write-Progress cmdlet, and I would argue appears to have been designed as such.
And if you think it's not that important, because it doesn't get that much use -- there's a reason it doesn't see much use: it's really hard to use decently well. A related sidenote here is that it probably needs some capability to measure things otherwise opaque to the user -- for example when Copy-Item is used, it's relatively difficult to figure out how to measure the progress of copying, say, a single large file. Something would likely need to be worked out for that to be more intuitive for users.
Environment data
Written as of PS 6.1.0