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
}
If we run that, we can tell where we’re at in our loop and calculate how many integers are left until our script is finished. But what if this isn’t a nice round number or what if it’s not numbers at all but names or credit card numbers job titles? “Give us Percentages!” is the cry from the mob and Ceasar will comply. Let’s break down what we’re doing with the Write-Progress cmdlet (hover over the parameters for info):

$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.

Combining the ForEach loop with our Progress added in looks like this:
#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)"
        }
    }
}
Now you can finally escape that time loop and add a little flare to your scripts by adding the Write-Progress to your repertoire.

OTHER POSTS YOU WANT TO READ

Index Scripts for Windows Search

So you just finished writing some code and you go to save your file. You summarize all of the important aspects this section of code contains into a nice, easy-to-read file name that your future self will immediately recognize. Fast forward to the future where you...

Array vs ArrayList (PowerShell)

For some tasks in life, being precise is a necessity. But most of us get away with rounding, paraphrasing, and hitting in the general vicinity most of the time. Depending on your personality, you may be one who strives for perfection and strains on every miniscule...

Spice Up HTML Emails with PowerShell – Part III

So far in this series we've fumbled our way around the kitchen and tried to wing it when sending HTML emails with PowerShell. It was clunky to say the least. We then went through our spice rack and built an HTML template, highlighting the nuances of each spicy element...

Spice up HTML Emails with PowerShell – Part II

In Part I of our scrumptious concoction we put our script into the oven to let it bake. But we forgot to add our secret sauce that's sure to leave our recipients drooling, which is clearly our goal. In this post we'll continue to spice up HTML emails with PowerShell...

Spice Up HTML Emails with PowerShell – Part I

I live in the South, specifically in God's country AKA TEXAS BABAY! There's plenty of amazing things about Texas and definitely some reasons to loathe being from Houston, but it's hard to knock our food. I mean, is there really even a debate between Whataburger vs...
%d bloggers like this: