Provide Progress for Your Script with a PowerShell Cmdlet

Provide Progress for Your Script with a PowerShell Cmdlet

  • Comments 4
  • Likes

Summary: Learn how to provide progress for your Windows PowerShell script using a simple cmdlet.

 

Microsoft Scripting Guy Ed Wilson here. I have spent much of the weekend working on games for the 2011 Scripting Games. I am almost ready to make an announcement about the dates. It will happen this coming week, so stay tuned. As is usually the case, when I am preparing for the Scripting Games, I look back over the things that I have written, and compare them with the tasks that will comprise the events of the Games.

I was looking over yesterday’s Weekend Scripter article, and decided that I need to add a bit to the what was said about using the Write-Progress cmdlet (an astute reader might see a connection between this and the fact that I was working on the Scripting Games).

One of the things that scripters often assume is that the Write-Progress cmdlet must be used to provide the percentage of completion of an operation. If the scope of the operation is not known ahead of time (such as the number of files or services to be enumerated), the Write-Progress cmdlet is not the correct tool for the job.

There are only two mandatory parameters for the Write-Progress cmdlet: Activity and Status. Therefore, it is perfectly permissible to use the Write-Progress cmdlet to display status information, but not to indicate measurable progress. An example of this is the BasicProgressDemo.ps1 script that appears here.

BasicProgressDemo.ps1

for($i = 1 ; $i -le 5 ; $i++)

{

Write-Progress -Activity "Counting to five" -status "`$i equals $i"

sleep 1

}

When the BasicProgressDemo.ps1 script runs, the Activity appears on the first line, and the Status appears on the second line. The cool thing about this is that the Status portion updates as it progresses through each loop. The progress bar appears but does not do anything. According to the help file, if the percentcomplete is not applicable (as in this case), I can use a value of -1, but in my testing, that did not appear to do anything. I was hoping that it would make the progress bar not appear, but that was not the case. The dialog box that appears when this script runs in the Windows PowerShell ISE is shown in the following image.

Image of dialog box that appears when script runs in PowerShell ISE

When the BasicProgress.ps1 script runs in the Windows PowerShell console, the progress bar does not appear (regardless if I set the value of percentcomplete to -1). The output shown in the following image is what appears in the Windows PowerShell console.

Image of script results without progress bar in PowerShell console

The figure above illustrates how to run a script in the Windows PowerShell console that has a space in the path. Notice that my folder HSG ARTICLES has a space in the name. This means that when I drag the file to the Windows PowerShell console, quotation marks are automatically placed around the path (due to the space). Therefore, if I were to press Enter, it would simply display the path, because it is a string. Therefore, I use the invocation operator (also known as the call operator)—the ampersand character—to run the script. The command to execute the script on my computer is shown here:

&"C:\Users\edwils\Desktop\HSG ARTICLES\BasicProgressDemo.ps1"

One of the cool things to do with the Write-Progress cmdlet is to use two of them at the same time. This is illustrated in the NestedProgressDemo.ps1 script. The trick to using two Write-Progress cmdlets at the same time is to give the first one an ID number. The second one specifies the first progress bar as the parentID. In this way, the first one will display on top, and the second one under the first. Without using the ID and the ParentID parameters, the two progress bars would display on top of one another. This is a great technique to use if you are connecting to a number of remote computers (that would be the first progress bar) and performing a number of operations on each computer (that would be the second progress bar). The NextedProgressDemo.ps1 script appears here.

NestedProgressDemo.ps1

$max = 5

For($i = 1; $i -le $max; $i++)

{

Write-progress -Activity "Counting I" -Status "`$i = $i" `

-percentcomplete ($i / $max*100) -id 1

sleep 1

For($j = 1; $j -le $max; $j++)

{

Write-progress -Activity "Counting J" -Status "`$j = $j" `

-percentcomplete ($j / $max*100) -ParentID 1

sleep 1

} #end for j

} #end for i

When the NextedProgressDemo.ps1 script runs, the dialog appears that is shown in the following image.

Image of dialog that appears when script runs

One thing that is cool to do is to use the Write-Progress cmdlet to time an operation. For example, if you are doing some performance testing, and you want to take your measurements at five-minute intervals, it might be nice to display the time remaining before the next measurement. I used to do these sorts of things manually, but it is easy to do this using the Write-Progress cmdlet. The TimerProgressDemo.ps1 script is an example of doing this. When the script runs, the seconds remaining are converted to minutes and seconds. The only indication of actual time is from the Start-Sleep command, which halts the progress of the script for one second per pass. The $max value of 300 will be 300 seconds, which translates to 5 minutes. The TImerProgressDemo.ps1 script appears here.

TimerProgressDemo.ps1

$max = 300

for ($i=$max; $i -gt 1; $i--) {

Write-Progress -Activity "Steeping Tea" -Status "Steeping" `

-SecondsRemaining $i

Start-Sleep 1

}

When the TimerProgressDemo.ps1 script runs in the Windows PowerShell console, the time remaining is displayed under the status message of “Steeping.” When this script runs in the Windows PowerShell ISE, the progress bar appears that is shown in the following image, but it is not used.

Image of results of script running in PowerShell console

Well, that is enough about progress bars. My new tea timer works great, and it says my tea is ready.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson, Microsoft Scripting Guy

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • There's a typo in NestedProgressDemo.ps1: It should be ($j / $max*100) in the second For loop instead of ($i / $max*100).

    Love your blog. Thank you for all the great articles.

  • @Lucas you are correct. I have updated the post. Thank you very much for catching it.

  • I get this when I included this sleep in a script...

    -SecondsRemaining : The term '-SecondsRemaining' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try

    again.

  • Very nice tutorial.
    Can you show how to integrate this to an actual script.

    Like copy-item