PSMonday #38: January 16, 2017

Topic: Foreach-Object 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.

We’re back today to wrap up the ForEach-Object cmdlet, with a few additional examples.

The Get-PSDrive cmdlet’s purpose is to return the logical drives on the computer, to include mapped drives, as well as drives exposed by various PowerShell providers. These include the alias drive — where the aliases are stored — the function drive — where functions in the current session are stored, and current user and local machine hives in the registry, as HKCU and HKLM, respectively.

Therefore, if you didn’t already know, you can search the registry from inside PowerShell, just as if it were a drive on the computer. That’s the purpose of a PSProvider. It can present various data stores, as though they were drives on the computer.

Here’s a filtered Get-PSDrive command, and the results it produces.

Get-PSDrive | Select-Object -Property Name,Root

Name     Root
----     ----
Alias
C        C:\
Cert     \
D        D:\
Env
Function
HKCU     HKEY_CURRENT_USER
HKLM     HKEY_LOCAL_MACHINE
S        S:\
Variable
WSMan

We did something like the upcoming example when we learned about the foreach language construct. In this example, we’ll deconstruct the objects produced by Get-PSDrive, in order to write out strings based on two properties of the objects — Name and Root. You probably wouldn’t want to do this, but nonetheless this example offers us a collection to loop through with the ForEach-Object cmdlet.

Get-PSDrive | ForEach-Object {
    "PSDrive Name : $($_.Name) || Root: $($_.Root)"
}

PSDrive Name : Alias || Root:
PSDrive Name : C || Root: C:\
PSDrive Name : Cert || Root: \
PSDrive Name : D || Root: D:\
PSDrive Name : Env || Root:
PSDrive Name : Function || Root:
PSDrive Name : HKCU || Root: HKEY_CURRENT_USER
PSDrive Name : HKLM || Root: HKEY_LOCAL_MACHINE
PSDrive Name : S || Root: S:\
PSDrive Name : Variable || Root:
PSDrive Name : WSMan || Root:

The next example begins by assigning the $Numbers variable a range of values from 1 to 10, thus making this variable an array.

$Numbers = 1..10
$Numbers

1
2
3
4
5
6
7
8
9
10

In each of the next two examples, we’ll make use of our numbers variable. This first example will use the foreach language construct that we covered prior to the ForEach-Object cmdlet. We set up the foreach using the foreach keyword and use $Number (singular), to use as the current value in the array.

Foreach ($Number in $Numbers) {

    Write-Output -InputObject "The current number is $Number."
}

The current number is 1.
The current number is 2.
The current number is 3.
The current number is 4.
The current number is 5.
The current number is 6.
The current number is 7.
The current number is 8.
The current number is 9.
The current number is 10.

In the below example, we’ll do the exact same thing as we did above, and iterate though each member in an array. The ForEach-Object cmdlet can do the same thing as the foreach language construct, it just does it a little differently. Instead of a variable you choose, we use $_, or $PSItem. Instead of foreach being the first word in the command, we pipe to the ForEach-Object cmdlet.

$Numbers | ForEach-Object {

    Write-Output -InputObject "The current number is $_."
}

The current number is 1.
The current number is 2.
The current number is 3.
The current number is 4.
The current number is 5.
The current number is 6.
The current number is 7.
The current number is 8.
The current number is 9.
The current number is 10.

In closing out ForEach-Object, let’s discuss some final differences with it, and the foreach language construct.

The foreach language construct is faster than the ForEach-Object cmdlet. This is because foreach puts the entire collection into memory before it begins to iterate over each item in the collection. This could be a problem, however, if there’s a chance you’ll run out of memory before you’re done processing the entire collection. While the ForEach-Object cmdlet may be slower, it’ll consume less memory.

We’ll continue with the For loop, next Monday.

Leave a Reply

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