How To Create PowerShell Progress Bars for External Tasks (Video Tutorial)How To Create PowerShell Progress Bars for External Tasks (Video Tutorial)

Learn how to use PowerShell to track and display the progress of external processes, such as file transfers, for better monitoring and visualization.

Brien Posey

January 24, 2025

8 Min View
ITPro Today

This tutorial demonstrates how to track the progress of an external process, like Robocopy, using a PowerShell progress bar. Although presented as a proof of concept, the technique can be adapted for various external processes.

Subscribe to ITPro Today’s YouTube channel for PowerShell tutorials and more.

The following transcript has been edited for length and clarity.

Transcript:

Brien Posey: Hello, greetings and welcome. I’m Brien Posey. In this video, I want to show you a technique I’ve been working on recently inside PowerShell. 

Progress Bars in PowerShell

Now, I'm guessing that most of you are probably familiar with the concept of a progress bar. A progress bar is simply a visual indicator showing how far into a particular task the system is so that you can estimate how much longer the task will likely take to complete. We've all seen progress bars. They come in a million forms, and you can easily create a progress bar in PowerShell. 

In PowerShell, progress bars are often tied to loops. The idea is that a loop must execute a certain number of times. You can create a progress bar that shows how many times the loop has run so that you can estimate how much longer the loop will take to complete the task.

Recently, I faced a bit of a dilemma. I needed to create a script that could track the progress of something that was happening outside of PowerShell. Honestly, I wasn't even sure if it was possible. But as it turns out, it is. It's not even overly difficult to do. That's what I want to show you in this video.

Related:Handle Long PowerShell Scripts With Background Jobs

An External Process Example (Robocopy)

So, what kind of external task are we talking about? 

Well, one of the things I do in my environment is create something called air-gapped backups. An air-gapped backup is just a backup written to removable media and then unplugged from the system. 

Now, air-gapped backups are not what I use for my primary backups. I base my primary backups on a continuous data protection system. I create air-gapped backups as a secondary backup, and the reason why is simple: Ransomware can't encrypt a backup that's not connected physically to the system. If I were to get a ransomware infection and it were to compromise my primary backups, I still have those air-gapped backups that I could fall back on as a second line of defense and hopefully get my data back.

You can create air-gapped backups in many ways. In my environment, the technique I've been using a lot involves a tool called Robocopy because it seems to work well.

If you're unfamiliar with Robocopy, it's a part of Windows but not a native PowerShell command. It's a command designed to be executed from the Windows Command Prompt. Robocopy does a great job of copying files. It gives you a tremendous number of options. So, even though I could use PowerShell-native commands to copy files as I'm creating my air-gapped backups, I find Robocopy more efficient and flexible. It's just easier to get the job done. 

Related:How To Make PowerShell Speak (Text-to-Speech .NET Tutorial)

But the question is: If Robocopy is a separate process, how do you track its progress using a PowerShell progress bar? Well, that's an interesting question to try to solve. Let me show you how I solved the problem. 

Intro to the PowerShell Script

Here's the script that I came up with:


$Source=“W:\EVA-104”
$Destination=“W:\Temp”

# Get the total number of files to copy (this is just a rough estimate)
$NumberOfFilesToCopy = Get-ChildItem -Path $Source -Recurse -File | Measure-Object | Select-Object -ExpandProperty Count
$NumberOfFilesCopied = 0

# Start the Robocopy process
Start-Process powershell -ArgumentList “-NoExit”, “-Command”, “robocopy W:\EVA-104 w:\temp; exit”

# Monitor the Robocopy process and update the progress bar
while ($NumberOfFilesCopied -lt $NumberOfFilesToCopy) {
	$NumberOfFilesCopied = Get-ChildItem -Path $Source -Recurse -File | Measure-Object | Select-Object -ExpandProperty Count
	# Update the progress bar
	$PercentComplete = ($NumberOfFilesCopied / $NumberOfFilesToCopy) * 100
	Write-Progress -PercentComplete $PercentComplete -Status “Copying files…” -Activity “File $NumberOfFilesCopied of $NumberOfFilesToCopy”

	Start-Sleep -Seconds 1
}

Write-Progress -Completed -Activity “Copy Process Complete”
    

 Now, I'll tell you straight-up that the script is not perfect. I designed it as a proof of concept rather than a bulletproof backup utility. Here, the script does a simple file copy as a proof of concept because I wanted to demonstrate this technique to you. The method itself is the significant part, not that this script will work in every situation (because I know it won't). For example, if there are files that already exist in the backup location, the script isn't going to work correctly. There are also a few other similar things that can cause the script to malfunction.

Related:How To Use PowerShell for Automated Event Response

Even so, the main thing that I wanted to show you isn't how to use Robocopy, but rather how to tie Robocopy (or any other external process, for that matter) to a progress bar. 

Setting up the Script

Let's look at how this works. 

First, the script defines my source and destination. In this case, I will copy some files from W:\EVA-104 to W:\Temp. So, I'm simply copying files from one folder to another for demonstration.

Get the total number of files to copy (this is a rough estimate)

  1. I set up a variable called $NumberOfFilesToCopy equal to Get-ChildItem. 

  2. I set the -Path to the $Source, which was W:\EVA-104. 

  3. I use -Recurse to check all these subfolders, as well. 

  4. I use Measure-Object and then Select-Object -ExpandProperty Count to give me the total number of files in the source directory. 

  5. I set up a variable called $NumberOfFilesCopied. I'm initially setting it to zero. 

Launching Robocopy as an External Process 

This section is where the script gets interesting. Technically, I could launch Robocopy from within PowerShell without additional code. However, for what I'm doing to work, Robocopy must run in an entirely separate process.

  1. I use the Start-Process cmdlet. The process I'm starting isn't Robocopy but PowerShell. So, I essentially start a new PowerShell session.

  2. I have my -ArgumentList. 

  3. The arguments I'm using are -NoExit (because I don't want that PowerShell session to close on me) and -Command. 

  4. The command is robocopy W: /EVA-104 W:/Temp; exit. It will cause that session to close once my file copy process has finished. So, when I run the script, a brand-new PowerShell window will open, Robocopy will launch automatically, it will copy all the files in the source to the destination folder, and then once that file copy process has completed, Robocopy will close.

The key takeaway is that we're doing that in an entirely separate process from where our script is running. 

Monitor the External Process and Update the Progress Bar

First, I have a while loop. So, I have: 

while ($NumberOfFilesCopied -lt $NumberOfFilesToCopy)

The $NumberOfFilesCopied is -lt (less than) the $NumberOfFilesToCopy—my total number of files.

Then, I execute this loop. I will do that as long as the total number of files I need to copy is less than the number I have copied. 

So, what am I doing within the loop?

First, I define a variable, $NumberOfFilesCopied, and set it equal to Get-Item -Path $Destination -Recurse -File. This is the exact same command that you saw earlier, except when I performed it earlier, I was looking at the source path, so I was counting the number of files that must be copied. Here, I'm looking at the destination. I'm counting the number of files that have already been copied.

Once I know the number of copied files so far, I can update the progress bar. I create a variable called $PercentComplete and set it equal to $NumberOfFilesCopied divided by $NumberOfFilesToCopy, then multiply it by 100 to get a percentage. Then, the Write-Progress cmdlet creates an update to a progress bar. So, I'm setting -PercentComplete to equal the $PercentComplete variable. I will set up the -Status to “Copying files…” and then the -Activity is going to be “File $NumberOfFilesCopied of $NumberOfFilesToCopy” so that we can keep track of the number of copied files vs. the total number of files that need copying.

Then, we have the Start-Sleep command. I'm setting it to one second. I use this command to slow the loop down a little. The loop will work in near real time but will have a one-second delay every time it progresses. I can ensure this works and doesn't overwhelm the system.

When the loop ends, we update the progress bar one last time. We set it to -Completed. The -Activity is “Copy Process Complete.” 

Running the Script

What does all this look like when it runs? Well, let's go ahead and look. 

I'll run the script and press Enter. I'll press R for Run. When I do, you see that separate window fire up, showing the Robocopy process. 

Here, in PowerShell, you can see my progress bar. It counts the number of files copied. When the copy process ends, that separate PowerShell session closes by itself, and then my script completes.

That's how you can monitor the progress of an activity that's happening in an entirely separate process. I'm Brien Posey. Thanks for watching.

About the Author

Brien Posey

Brien Posey is a bestselling technology author, a speaker, and a 20X Microsoft MVP. In addition to his ongoing work in IT, Posey has spent the last several years training as a commercial astronaut candidate in preparation to fly on a mission to study polar mesospheric clouds from space.

https://brienposey.com/

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like