One thing I like about scripting/programming in general is that I never seem to have it all together before I learn about some magical piece of code, which I was unaware even existed, and it goes on to change my life forever. Some of these are quite bigly and others just make small improvements to my quality of [code] life. This discovery is usually accompanied with huge smiles, shouts of “eureka,” and conversations with my wife and friends who have no idea what I’m saying (nor do they care) but pretend to listen and nod in agreement with smirks and smiles at strategic points. One such experience was with the professional Progress Bar! Nothing screams legit-ness more than a bar of progress to spice up your scripts.
\\\A Fart In A Fan Factory
So there’s nothing like writing a loop, firing off that bad boy, and then having no idea where you’re at, what’s going on, or what it’s actually doing.
Is it even working?
Who knows?!
Sometimes minutes can turn into hours only to find out that something didn’t work as expected and your WMD was a dud. Nothing worse than doing this while somebody is standing over your shoulder expecting fireworks as you nervously try to downplay the situation. Reminds me of the good ol’ days of burning a DVD, only to find out hours later that the write failed and now you’re left in a puddle of your own tears holding onto a dangerous frisbee with a hole in the center.
\\\Usual Suspects
To remedy this, we typically write output at certain points in our script/loop to give us an idea of where we’re at and what we’re doing. If it’s a straightforward cmdlet, we could turn on verbose output to see that in the pipeline. We could even use try/catch to capture error messages or let us know when something was successful. I’ve used a combination of all of these methods at various times depending on what I’m needing, but I recently discovered the holy grail of notifications…okay, so maybe it’s not the holy grail but it’s super helpful and adds a little pizazz to our life, and who doesn’t want more pizazz? Amiright??
\\\Now that’s Progressive
I first started out exploring the random thought of how I could write output that would act as a “progress bar” of sorts in a loop. As with many of my previous ideas, this one quickly died when I started trying to think it through…but my ol’ pal Google came through with results of a cmdlet previously unknown to me: Write-Progress.
Now, depending on your level of motivation and how many cups of coffee you’ve had, you can get quite fancy with it but today we’ll look at a couple scenarios of how we could use this to our aid in our quest to script the world.
\\\Scenario 1 – The Simple Life
Okay pilgrim, let’s first look at a simple loop where we start to make some progress (puns always intended). We’ll define our array quickly by using the “..” between 2 integers so PS will do the rest for us. Then we can loop through each integer in the array and do something simple like write some output for each one. Unless you’re still rockin’ that Intel P3 proc on 64KB of memory, your computer will probably process this quicker than you can say fünfhundertfünfundfünfzig. To counter this, we’ll add a Start-Sleep for 10 miliseconds to actually see the progress taking place.
Here’s what we have so far:
#Tales from the ForEach Loop
$ArrayOfNumbers = 1..200
foreach($I in $ArrayOfNumbers){
Write-Host "$I) Robots, time travel, and alternatve universes..."
Start-Sleep -Milliseconds 10
}
$Percent = $I/($ArrayOfNumbers.Count)*100$Percent \\ This gives us a percentage that's calculated using the integer in each iteration of the loop. Ex: (5/200)*100=2.5
Write-Progress -Activity ‘Magic’-Activity \\ This is like the title of the Progress Bar -PercentComplete $Percent -Status “$Percent% Complete”-Status \\ This is combining the calculated Percentage plus the percent sign and the word 'Complete'. Ex: 5% Complete -CurrentOperation ArrayOfNumbers-CurrentOperation \\ This is where you name the activity that you're referring to. Remember the Sims and all of the hilarious loading progress messages? Classic.
#Tales from the ForEach Loop
$ArrayOfNumbers = 1..200
foreach($I in $ArrayOfNumbers){
Write-Host "$I) Robots, time travel, and alternatve universes..."
Start-Sleep -Milliseconds 10
$Percent = $I/($ArrayOfNumbers.Count)*100
Write-Progress -Activity 'Magic' -PercentComplete $Percent -Status "$Percent% Complete" -CurrentOperation ArrayOfNumbers
}

\\\Scenario 2 – Loop-ception
Why have only one dream when you can have a dream inside of a dream? Write-Progress also provides a way for us to have multiple progress bars. Think of one being the overall script (outer progress bar) and the sub progress bar (inner progress bar) being individual sections within the script. For our demonstration, let’s take Scenario 1 and then add another loop that goes through each iteration of our $ArrayOfNumbers and multiplies it by a defined set of numbers ($Multipliers) and spit out any products that contain a 6.
A couple of key notes here:
- In order to clean up our output a little, comment out our initial Write-Host that tells us which integer we’re currently on by putting a # in front of the line of code. We’ll only Write-Output if the product contains a 6.
- Calculating the percentage when your array is sequential numbers is easy, but our $Multipliers array isn’t a counter, it’s 4 specific numbers. To get our calculation correct, we can use the index (which iteration of the array that we’re currently on) so we can math flex and calculate the percentage for our inner progress bar. For example, if we’re on the 3rd number in the array, that would be (3/4)*100, or 75%.
- Our second Write-Progress cmdlet is pretty similar to our first but with one extra parameter: -ID. Giving this progress bar another ID is what allows us to have an outer and inner progress bar at the same time. Without this, it would update our outer progress bar.
Putting it all together looks like this (You can also view this file on GitHub):
#Tales from the ForEach Loop
$ArrayOfNumbers = 1..200
$Multipliers = @(2,10,50,1000)
foreach($I in $ArrayOfNumbers){
#Write-Host "$I) Robots, time travel, and alternatve universes..."
Start-Sleep -Milliseconds 10
$Percent = $I/($ArrayOfNumbers.Count)*100
Write-Progress -Activity 'Magic' -PercentComplete $Percent -Status "$Percent% Complete" -CurrentOperation ArrayOfNumbers
foreach($M in $Multipliers){
$Product = $I * $M
Start-Sleep -Milliseconds 50
$Index = [array]::IndexOf($Multipliers, $M)
$Percent2 = $Index/($Multipliers.count)*100
Write-Progress -Activity 'Multi' -Id 2 -PercentComplete $Percent2 -Status "$Percent2% Complete" -CurrentOperation Multiplication
If($Product -like "*6*"){
Write-Host "$I * $M = $Product (contains a 6)"
}
}
}
