Getting Started - Loop-the-Loop

Loop used in Part 4

We actually ended up using a loop in Part 4 to iterate through each disk and display information regarding the disk.

Code for loop used in Part 4:

Foreach ($disk in $disks) {

                Write-Host `n"Device ID    : $($disk.DeviceID)"
                Write-Host ("Free Space   : {0:N2} GB" -f $($disk.FreeSpace / 1GB))
                Write-Host ("Total Size   : {0:N2} GB" -f $($disk.Size / 1GB))
                Write-Host ("% Free       : {0:P0}   " -f $($disk.FreeSpace / $disk.Size))
                Write-Host "Volume Name  : $($disk.VolumeName)"
                Write-Host "Drive Type   : $(Get-WMIInfo -lookup 'drivenumber' -typeNumber $disk.DriveType)"`n

            }

This is called a ForEach loop and what it does is iterates through and array of objects, allowing you to declare the item as well as the array or collection.

ForEach ($item in $collection) { $item.Property }

In this case the item we declare is $disk, from the array/collection $disks.

What this allowed us to do was go through each disk, and for each disk display that current item's information individually. 

Handling individual items

Since $disk represents the current item in the loop, we can use $disk.Property to display the properties we want. The last line in this example uses the Get-WMIInfo function to assign the drive type text to the number we supply. That happens once for each item in the loop, therefore different drives (CD-ROM, HDD, etc) will return as different types.

The many different loops in PowerShell

There are many different types of loops in PowerShell. You can actually use any of them to perform the same task. There is usually a "best loop" for any given task, however. 

To get started, let's create and save part5.ps1 in C:\PowerShell (or wherever you prefer).

Note

If you run code that performs an infinite loop in PowerShell, use CTRL+C to break out of the loop.

The ForEach loop

What's it do?

The ForEach loop in PowerShell iterates through an array/collection. It allows you to define the element or item you wish to use as the placeholder for the current object in the loop.

Loop setup

The ForEach loop is setup as follows:

ForEach (item/element in array/collection) {

Do-Stuff

}

Element can be anything you specify. It makes sense to make it reflect what is being handled as the current item, however. 
Array is the object/array/collection you want to iterate through.

Example

Copy and paste the following into part5.ps1 (or the PowerShell console):

$processes = Get-Process

$i = 1
ForEach ($process in $processes) {

    Write-Host "Process[$i]'s Name is $($process.Name)"

    $i++

}

Here's the output of the code above:

In this example we declared $processes to hold the results of Get-Process$i as 1, then our ForEach loop with $process as the placeholder, and finally $processes as the item to iterate through.

The action we take is to Write-Host the current value of $i, and the current element's ($process)'s Name via $($process.Name).

We then take the final action of iterating $i by 1 via $i++.  $i++ is simply a shortcut that tells PowerShell to add one to the current value of $i

ForEach-Object

There's a pipeline variation of the ForEach loop named ForEach-Object.

To use it you would simply run the command you want, and then pipe it to ForEach-Object. You would then use the special placeholder variable in PowerShell ($_) to take action on the current element in the array. 

Here is an example:

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with $i = 1) as a selection, rather than the whole script.

$i = 1
Get-Process | ForEach-Object {

    Write-Host "Process[$i]'s Name is $($_.Name)"
    $i++

}

This will perform the same actions as the other loop, but in a different way.

I generally like to store commands I'm calling into variables, and because of that I use the ForEach loop more. ForEach-Object does have it's place though, especially when you're running advanced commands and you need to perform actions from piped in input.

When to use a ForEach loop

I use a ForEach loop when there is an action I want to take on an array of items. The action could be anything from deleting specific files, or merely displaying information.

The for loop

What's it do?

The for loop performs actions until a specific condition is met.

Loop setup

The for loop is setup as follows:

for (init;condition;repeat) {

Do-Stuff

}

Here's what the init, condition, and repeat represent:

init = The statement/action that runs first (once). Typically it is the variable to be initialized and used in the loop.
condition = Statement that must be true for the loop to continue running
repeat = Action to take after a loop cycle

Examples

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with for ($i=1;$i -le 15;$i++) {) as a selection, rather than the whole script.

for ($i=1;$i -le 15;$i++) {

    Write-Host "This is the color for [$i]" -ForegroundColor $i

}

You should see the following output:

For this example we set the init as $i=1. This initializes $i with the value of 1.

We then set the condition as $i -le 15. What that states is the loop will run as long as $i is less than (or equal to) 15.

Finally, we set the repeat to $i++. 

Write-Host takes 1-15 as values for the ForeGround color, which this loop iterates through.

For loop flexibility

You can actually specify any or none of the conditions for initcondition, and/or repeat.

For example, this works:

for () {Write-Host "Wheeeeeeeeeeeeeeee!"}

Which results in:

I'll note again that CTRL+C is your friend when your loop is infinite and you want to break out of it in PowerShell.

You can also specify the various elements outside of the loop statement declaration.

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with $i = 0) as a selection, rather than the whole script.

$i = 0

for (;$i -le 20;) {

    Write-Host "`$i is [$i] iterations old!"

    $i++

}

Note: In this example it is important to understand that there are semicolons around the condition. That is to tell PowerShell there is no init specified in the for loop statement, that there is a condition, and finally that there is no repeat defined.

Here's the output:

When to use a for loop

I generally use for loops when I want to run the same set of code multiple times for various reasons. 

Remember the ForEach loop with Get-Process earlier?

One of the awesome things about PowerShell is you can do one thing many different ways.

Here's a for loop iterating through $processes its own way:

$processes = Get-Process
for ($i = 0;$i -le $processes.count;$i++) {Write-Host "Process[$i]'s Name is $($processes[$i].Name)"}

We set the the condition to be when $i is less than (or equal to) $processes.count.

We then modify the Write-Host statement a bit to reflect the current element in the $processes array via $processes[$i]. All arrays in PowerShell start with 0, which is why we set the init as $i = 0.  

The While loop

What's it do?

The While loop in PowerShell performs actions while a condition is true.

Loop setup

While (condition) {

Do-Stuff

}

The setup is easy for this one! Condition reflects any statement / expression that is true.

Example

For this example we'll be using Notepad.exe. If you have any Notepad windows open, close them!

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with $notepad = Get-Process Notepad) as a selection, rather than the whole script.

$notepad = Get-Process Notepad

While ($notepad.Count -le 5) {

    Write-Host "Starting Notepad, current count is: $($notepad.Count + 1)"

    Start-Process Notepad.exe

    $notepad = Get-Process Notepad
    
}

Here is the result:

In this example we declare $notepad as the result of Get-Process Notepad. We then start the loop with the condition that $notepad.Count is less than (or equal to) 5

When the condition is true we use Write-Host to display the current number of Notepad windows open, open another Notepad window via Start-Process, and then declare $notepad as the result of Get-Process Notepad. That last step is perhaps the most important. If we did not do that, we'd have an infinite loop, and not a fun one.

Note:

We will use Notepad as an example in another loop. To close all open Notepad windows at once, run:

Get-Process Notepad | Stop-Process

BE SURE TO INCLUDE NOTEPAD IN GET-PROCESS!

When to use a While loop

I generally use while loops to perform actions I need to perform, while a specific condition is true. This could be while a specific process exists that you would like to close, or while PowerShell jobs exist. We haven't covered jobs yet, but we will do that in a later post!

The Do While loop

What's it do?

The Do While loop in PowerShell performs actions while a condition is true. The difference between Do While and While is that even if the condition is not true, the Do actions still run at least once. Whereas with the While loop the actions do not ever run if the condition is not true.

Loop setup

Do {

Do-Stuff

} While (condition) 

For the Do While loop we declare Do { Do-Stuff } for our action, and then finally the While condition afterwards.

Examples

Here is an example demonstrating that the Do actions always run before the condition is evaluated.

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with $i = 14) as a selection, rather than the whole script.

$i = 14

Do {

    Write-Host "This will still run once! `$i = $i"

} While ($i -gt 15)

$i is never greater than 15, yet the Do code still executes at least once.

Here's another example of a Do While loop in action:

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with $i = 0) as a selection, rather than the whole script.

$i = 0

Do {

    Write-Host "Now we're cookin'! `$i = $i"
    $i++

} While ($i -le 15)

This will add one to $i while $i is less than (or equal to) 15.

When to use the Do While loop

I use the Do While loop when I want to have the While loop going, yet no matter what need to perform the actions of the Do statement at least once.

The Do Until loop

What's it do?

The Do Until loop performs actions UNTIL a condition is true. This is the opposite of what we're doing with the Do While loop. Like the Do While loop, however, the Do statements are run at least once.

Loop setup

Do {

Do-Stuff

} Until (condition)

The setup for this is very similar to the Do While loop. The only difference here is we're using Until, not While

Example

Copy and paste the following into part5.ps1 (or the PowerShell console):
Run the code (starting with Do {) as a selection, rather than the whole script.

Do {

    $notepad = Get-Process Notepad

    Start-Process Notepad.exe

    Write-Host "Starting Notepad, current count is: $($notepad.Count + 1)"

    $notepad = Get-Process Notepad


} Until ($notepad.Count -eq 5)

This should execute Notepad exactly 5 times, given that it was not open before running the code.

Notice how we changed the condition to be -eq and not -le. So Until $notepad.Count equals 5, we're performing the loop actions of Do.

When to use the Do Until loop

I seldom have used the Do Until loop, but it has its place. You generally would use it when you need to run commands that should execute until a specific condition is true. The condition could be that a specific process is running, or a number you're keeping track of reaches a specific value.

Comparison Operators

I've use a few comparison operators in these examples. Comparison operators evaluate values you place on either side. Here are some examples.

-eq
The -eq comparison operator evaluates whether one value equals another. For example:

1 -eq 1

The above example would return True 

-ne
The -ne comparison operator is the opposite of the -eq comparison operator. For example:

1 -ne 1

The above example would return False

-gt
The -gt comparison operator evaluates values to see if one is greater than the other. For example:

2 -gt 1

The above example would return True

-ge
The -ge comparison operator evaluates values to see if one is greater than or equal to the other. For example:

2 -ge 2

The above example would return True

-lt
The -lt comparison operator evaluates values to see if one is less than the other. For example:

1 -lt 2

The above example would return True

-le
The -le comparison operator evaluates values to see if one is less than or equal to the other. For example:

2 -le 2

The above example would return True

-like
The -like comparison operator evaluates values to see if one is like the other, allowing a wildcard comparison to take place. For example:

'onetwothree' -like '*one*'

The above example would return True

-notlike
The -notlike comparison operator evaluates values to see if one is not like the other, allowing a wildcard comparison to take place. For example:

'onetwothree' -notlike '*one*'

The above example would return False

There's more!

For a deeper dive into comparison operators, use this command:

Get-Help About_Comparison_Operators

You could also check out this link: http://ss64.com/ps/syntax-compare.html

Homework

  • Pick one of the loop examples and get it working with each of the different loop types. (It's possible!)

  • Learn more about comparison operators

I hope you've enjoyed the series so far! As always, leave a comment if you have any feedback or questions!

-Ginger Ninja

[Back to top]