PSMonday #36: January 2, 2017

Topic: Foreach II

Notice: This post is a part of the PowerShell Monday series — a group of quick and easy to read mini lessons that briefly cover beginning and intermediate PowerShell topics. As a PowerShell enthusiast, this seemed like a beneficial way to ensure those around me at work were consistently learning new things about Windows PowerShell. At some point, I decided I would share these posts here, as well. Here’s the PowerShell Monday Table of Contents.

Back again to discuss, and close out, the foreach language construct. This is the first looping construct we’ve seen so far.

Today, one of the things we’ll do, is nest a foreach inside of a foreach. In case it hasn’t been mentioned yet, all of these language constructs can be nested inside of each other. In fact, this is often a requirement. It all depends on the problem, or problems, that you need to solve. This is a great reason to ensure you understand all of the conditional constructs.

We’ll start today’s PSMonday by creating two variables. One, the Colors variables will hold the same four colors from last week. The second variable, the Animals variable, will also hold four values: dog, cat, bird, and frog. Take a look at the below example, and the explanation further below.

$Colors = 'red','blue','green','gray'
$Animals = 'dog','cat','bird','frog'

Foreach ($Color in $Colors) {
    Write-Output -InputObject $Color

    Foreach ($Animal in $Animals) {
        Write-Output -InputObject $Animal
    }
}

red
dog
cat
bird
frog
blue
dog
cat
bird
frog
green
dog
cat
bird
frog
gray
dog
cat
bird
frog

Admittedly, this is a little difficult to follow. Before we walkthrough what’s happening here, let’s modify how we display the values in the Color variable. Additionally, we’ll modify how we display the values in the Animal variable, as well. This will help us better follow these nested foreach loops. Colors will have two dashes on both sides, and animals will have a right, angle bracket before the animal name.

Foreach ($Color in $Colors) {
    Write-Output -InputObject "--$Color--"

    Foreach ($Animal in $Animals) {
        Write-Output -InputObject "> $Animal"
    }
}

--red--
> dog
> cat
> bird
> frog
--blue--
> dog
> cat
> bird
> frog
--green--
> dog
> cat
> bird
> frog
--gray--
> dog
> cat
> bird
> frog

From the previous examples, you may already be able to determine exactly what’s happening. In case you don’t, let’s walk through the looping that is taking place.

After we set the two variables, Colors and Animals, we enter the first foreach. In here, we echo the first color. Then we enter the nested, or the second foreach loop, and loop through all four animals. We then return to the outermost foreach, and echo the second color. Again, we loop through all the animals. We continue this until we’re all out of the colors in the Color variable, and we do a final loop through the animals.

Here’s the last example. Although we won’t be working with nested foreach loops, I think it’s important to see a potential, real-world example. With Get-Service, and most other properly written cmdlets and functions, we can pipe to the Select-Object cmdlet, and return just the properties in which we’re interested.

Get-Service | Select-Object -Property Name,Status -First 3

Name                       Status
----                       ------
AdobeARMservice           Running
AdobeFlashPlayerUpdateSvc Stopped
AeLookupSvc               Stopped

Let’s assume we don’t want to return objects — for some reason — and instead just want to return strings made up of the two above properties, separated by a colon. It’s not really practical, but it will provide a bit more of a real-world foreach example. To accomplish this, we’d need to loop though the results of Get-Service.

Foreach ($Service in Get-Service | Select-Object -First 3) {
    "$($Service.Name) : $($Service.Status)"
}

AdobeARMservice : Running
AdobeFlashPlayerUpdateSvc : Stopped
AeLookupSvc : Stopped

As we can see, the items in our collection (the $Service in Get-Service), can be taken directly from the results of a command, without the need to assign everything to a variable first. While this made not always be the best idea for the sake of readability, it’s something you may see one day.

Up next week, is the ForEach-Object cmdlet.

Leave a Reply

Your email address will not be published. Required fields are marked *