Stop Looking Forward, My Thoughts

Don Jones, one of the bigger names in the PowerShell community, had an great post on his personal website. It was entitled, Stop Looking Forward. I liked it.

The idea behind his post was to stop looking to advance yourself and your career long enough, to give back to your community. Coming from Don, we can all safely assume, he’s speaking from experience. Whether he knows it, or not, he taught me for free, a time or two. It’s his job now, and so there needs to be dollar signs at some point in his help cycle, but I don’t think for a moment, that that’s what this was always about. It’s quite believable that he wants all of us to succeed. Writing is a talent, and so paying for his ability to explain these topic seems justifiable.

I remember right where I was standing when I decided I was going to give back to the PowerShell community, outside of just helping on various PowerShell forums, where I had been both learning and offering assistance, as I was able. No joke, but reading forums is a great place to learn. Before you know it, you’ll be able to help others learn those things you already have.

I was washing my hands in the bathroom sink at work, after I had recently read an article from a PowerShell MVP. He had a website,, where he occasionally shared PowerShell themed articles. That was it, I thought. I’m going to register, and I’m going to write about PowerShell, too. I always had this concern that I didn’t know enough yet, but I went ahead and I did it anyway. You can likely give back to the PowerShell community before you even think you’re ready. I started well before I thought I would.

I wrote my first few posts on, felt quite confident, and then read an article from Jeffery Hicks. In his post, he clearly stated not to do rewrites on the help files, as they were already there. Damn.

It was around June 2014, and I accepted that challenge. Unbeknown to Jeffery, as though it would’ve made a difference anyway, I never did a help rewrite again. Instead of doing help rewrites, I just started writing. I’d find something interesting and I’d share it. I make something I wanted to keep, and so I’d post it for others to read about and learn from. It’s been two and half years now and this is my 181st post. That’s an average of greater than 6 posts per month. There’s no ads, or sponsors, and I don’t see a dime. I was at 100 posts in April 2016 when I was chatting with Neema, a Microsoft employee, about their MVP program at the PowerShell + DevOps Global Summit 2016. I’ve written approximately 9 posts per month since then.

For those that haven’t asked, or have made an incorrect assumption, I’ve never been a Hero, or a Microsoft MVP. After the Phoenix PowerShell Saturday in October 2016 — where I actually spoke — I answered a question from Will Anderson: “No, I’m not an MVP.” I was impressed, however, as I had convinced an MVP, that I was also an MVP, even when I wasn’t.

I’ve said it a few times now: I set out to be an MVP. I set out to add my name to the list of PowerShell Heros. It’s about me in some way — I can agreed to that — but it all started with this desire to give back to others that were like me. I learned from the forums, so I helped on the forums; I learned from #PowerShell on Twitter, therefore, I contributed to Twitter; I learned from PowerShell blogs and started my own. A recognition would clearly indicate that setting out to help others, did in fact, help others. It would validate that I stopped looking forward, to help those around me. Those around me at work? Well, many of them get a weekly, PowerShell related email from, yours truly. I’ve written nearly 40 of them and plan to take it all the way to 52 — a full year of hey-learn-about-PowerShell-before-you-wish-you-did emails. If we want to promote from within, then let’s give those junior level, lower tier employees some skills; let’s get them interested in what we’ve found so fun. Let’s give back like Don has, like Jeffery has, like Will has, and June, too.

I’m going to quote Don, here — “At the end of the day, we should all measure our success by the impact we’ve made on our world, and in our communities.” I have no idea how long PowerShell will be around, or even how long I’ll be around, but I believe I’ve made an impact on my community. I’ve certainly set out to do that. As Don would, I urge you to do the same, if you don’t already.

Don says it better, so if you haven’t, go read that post already.

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
----     ----
C        C:\
Cert     \
D        D:\
S        S:\

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 : 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


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.

Convert Inches to Feet, and Inches

My blog serves several purposes. One of which I’ve mentioned before, is to keep things around I may want later. That’s why we’re back today. While helping on a TechNet forum post, I wrote the below function.

This function’s purpose is to convert inches between 56 and 76 to their <feet>'<inches>” equivalent. This means if you send in 56, you’ll get back 4’8″, if you send in 60 you’ll get 5’0″, if it’s 73 you’ll get 6’1″. The reason it’ll only take 56 to 76 inches is due to the initial requirements in the forum post. If you had a purpose for this function and wanted it to accept more or less inches, you’d have to modify the ValidateRange attribute to different minimum and maximum values, or remove it altogether. If you can use this function, then here it is.

Function Convert-InchToFeetInch {
    Param (

    $TotalFeet = [int](($Inches / 12).ToString().Split('.')[0])
    $RemainingInches = $Inches - ($TotalFeet * 12)


This first example will loop through all the possible values from 56 to 76 using the ForEach-Object cmdlet. As it does that, it’ll write out the number of inches it’s converting, as well as the feet and remaining inches in the aforementioned format.

56..76 | ForEach-Object {
    "$_ inches is $(Convert-InchToFeetInch -Inches $_)"

56 inches is 4'8"
57 inches is 4'9"
58 inches is 4'10"
59 inches is 4'11"
60 inches is 5'0"
61 inches is 5'1"
62 inches is 5'2"
63 inches is 5'3"
64 inches is 5'4"
65 inches is 5'5"
66 inches is 5'6"
67 inches is 5'7"
68 inches is 5'8"
69 inches is 5'9"
70 inches is 5'10"
71 inches is 5'11"
72 inches is 6'0"
73 inches is 6'1"
74 inches is 6'2"
75 inches is 6'3"
76 inches is 6'4"

These next examples simply use the function outside a looping construct. You provide a number of inches to the Inches parameter, and the function will return the converted value. That’s it. Maybe it helps you, and maybe I can find it if I ever need it.

Convert-InchToFeetInch -Inches 56 # 4'8"
Convert-InchToFeetInch -Inches 60 # 5'0"
Convert-InchToFeetInch -Inches 68 # 5'8"
Convert-InchToFeetInch -Inches 73 # 6'1"
Convert-InchToFeetInch -Inches 76 # 6'4"


PSMonday #37: January 9, 2017

Topic: Foreach-Object

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.

Now that we have a basic understanding of the foreach language construct, we can move on to the ForEach-Object cmdlet. First, let’s consider the name of the cmdlet, as there are some similarities with some others. The noun — remember the verb-noun naming convention — is object. Let’s find all the commands with that same noun.

Get-Command -Noun Object | Select-Object CommandType,Name

CommandType Name
----------- ----
   Function Show-Object
     Cmdlet Compare-Object
     Cmdlet ForEach-Object
     Cmdlet Group-Object
     Cmdlet Measure-Object
     Cmdlet New-Object
     Cmdlet Select-Object
     Cmdlet Skip-Object
     Cmdlet Sort-Object
     Cmdlet Tee-Object
     Cmdlet Where-Object

If you’ve used some of the above commands, then you may recognize that many of these commands are used with the pipeline. This is to say, that we often send a command’s resulting objects to one of these commands.

In fact, take a look at the Get-Command, command we ran: We piped the objects created by Get-Command to the Select-Object cmdlet for further processing and filtering. That’s how we’ll use ForEach-Object, too; we’re always going to pipe to it.

Let’s begin with some conceptual examples of the ForEach-Object cmdlet. As we saw in a previous PSMonday, the first part of this example is the Microsoft help’s suggestion, and the second part of this example is how you’ll see me use the cmdlet.

<command> | ForEach-Object {<command_block>}

<command> | ForEach-Object {

As we’ve stated before, always use full cmdlet names unless you’re using the command in a onetime use scenario. If you’re pounding out PowerShell commands with no intention of keeping them, then you can use either of the ForEach-Object aliases, as demonstrated below. This is important: foreach is an alias for the ForEach-Object cmdlet when it is used in a pipeline. When it’s not used in a pipeline, such as we saw in the last two weeks, it’s treated as the foreach language construct, and not as an alias for ForEach-Object. This can cause some confusion, and so it’s important to understand this distinction.

<command> | foreach {

<command> | % {

Before we put things back on hold until next Monday, let’s take a look at a real-world example. Both of the following parts of this example do nearly the same thing. The difference is that one, the second half includes the string “Item: ,” and two, it uses the $PSItem automatic variable, instead of $_. This variable — regardless of which you use — represents the current object in the pipeline. $PSItem was introduced in PowerShell 3.0.

1,'string1',2,'string2' | ForEach-Object {
    Write-Output -InputObject $_

Write-Output -InputObject '------'

3,'string3',4,'string4' | ForEach-Object {
    Write-Output -InputObject "Item: $PSItem"

Item: 3
Item: string3
Item: 4
Item: string4

In the above example, we sent four objects — two integers and two strings — down the pipeline to each of the ForEach-Object cmdlet examples. In looking at the first part of the example, $_ was 1 the first time the ForEach-Object cmdlet ran, it was ‘string1’, the second time the ForEach-Object cmdlet ran, 2 the third time, and ‘string2’ the final time the loop executed.

We’ll be back next week to help solidify how we use the ForEach-Object cmdlet.

Get-TMVerbSynonym 1.4

Notes: Download link at the bottom of this post.

One of my favorite PowerShell community members, June Blender, posted a question on Twitter. While it wasn’t directed at me, I couldn’t resist. She wanted the approved verb options for the verbs “populate”, “fill in”, or “load”. I couldn’t help myself, because I wrote a function for this very task!

The Get-TMVerbSynonym function’s purpose is to find synonyms for verbs and return whether they’re approved, or not. Well, her Tweet was all it took to finally make some overdue changes, to include getting it posted on the PowerShell Gallery. As I called it in one of my follow up tweets, when June asked where it was then published, I said it was a “TechNet leftover.”

Well, not anymore.

It’s since been updated to version 1.4 and placed on the PowerShell Gallery. The above image was what I posted when it was in version 1.3. This means that it doesn’t reflect two of the newest, view able changes. The Verb property now indicates the verb it’s checking, and the old Verb property has been renamed to Synonym. This was included to support some other potential updates for an even newer version. Anyway, this means it’s up to five properties, so pipe to Format-Table -AutoSize in order that the results can be easily read.

Additionally, it now includes something I always wanted it to have: an Approved, switch parameter. This means there’s no piping to Where-Object to filter the function to only show the approved synonyms. Here’s an example of the function in action, both with, and without the Approved, switch parameter.

Download it now manually, or use Install-Script -Name Get-TMVerbSynonym.

Be Twice the Employee

One of the things I like the most about PowerShell, is that it means I can work more than 40 hours per week. Now, what I don’t mean is that I work on PowerShell outside of the 40 hour week — although, I definitely do, because I’m hooked — but rather that PowerShell works for me, when I’m not even working.

For example, every day from 3:00 to roughly 3:45 a.m., it’s working for me. It’s doing what I told it to do; it’s executing; it’s taking a job I never wanted to do manually and seeing that it gets completed. Me? What am I doing during that time? Well, unless something’s gone seriously wrong, and I’m not just talking about work, then I’m asleep. I’m working and I’m sleeping, at. the same. time.

Ever expand the properties of an Active Directory group at 3 a.m.? If you did that in the GUI, then you were awake. Ever click that Members tab that early in the morning? If so, I bet you had wished you were sleeping. Ever remove a user from an AD group just hours before the sun was back up? I do it every day at 3:00 a.m., but I don’t.

This is one of the reasons that PowerShell is so powerful. It makes you more efficient. It makes you twice the employee. If there’s PowerShell for it, I can do it faster; I can do it more efficiently than the next person that doesn’t use PowerShell.

If you work, or want to work, in the Information Technology arena — both with Windows and now without Windows (yes, it’s likely come to your operating system of choice) — then make PowerShell a part of your skill set. Read Learn Windows PowerShell in a Month of Lunches, Third Edition; watch the Microsoft Virtual Academy PowerShell 3.0 Jump Start, and yes, I’m aware PowerShell 5.1 for Windows is coming this month. That set of videos is still worth the time.

Be twice the employee, too. Complete tasks no one would want to do, while you’re sleeping. I’m going to do it again tonight.

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


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"

> dog
> cat
> bird
> frog
> dog
> cat
> bird
> frog
> dog
> cat
> bird
> frog
> 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.

PowerShell Resolutions 2017

I’ve followed Boe Prox’s lead the last two years in making some PowerShell resolutions (2015 and 2016). Let’s start with how I did, and didn’t do, in 2016.

  • DSC genius: No…, I wouldn’t call myself a genius yet, as I still feel like I have plenty to learn. I look forward to getting my hands on the DSC Book being written by Don Jones and Melissa Januszko. Let’s hope work will cover the cost on that one.
  • Stay active on PowerShell forums: Yes. I’ve continue to assist on (not as much as the others…), Microsoft TechNet, Reddit, and even Facebook when there’s time.
  • Read PowerShell in Depth: In progress. This is on hold as I finish up a copy of Amazon Web Services in Action. My employer is getting deep in the world of AWS, and I opted to be the AWS lead for my team.
  • First module up on the PowerShell Gallery: Yes (and a script, too). I wrote a two function module that allows for foreground and background colors in the ConsoleHost without the need for Write-Host. The script, is a rewrite on a game I wrote a couple years ago called The 1 to 100 game. Check out the above links for more information.
  • Nano Server: I wouldn’t consider myself much of a resource, but I’ve done some experimentation. There’s more to do here.

There’s one thing in particular that I didn’t even think was possible this year. In April, I was asked to speak at the Phoenix PowerShell Saturday event. I didn’t see that one coming, but sure enough, I did that in October, and I think that deserves mentioning.

I’ve continued to stay active on Twitter, and in the close of the year, have had several popular posts there. I’m still actively blogging here on my site (-gt 170 posts now), and linking them on Twitter. I learned a good amount by reading PowerShell content linked on Twitter, and so I’m still giving back here, and then there.

Oh, I also started what I called PSMonday at work. Each Monday I send out a brief PowerShell related email to help encourage those around me at work to embrace PowerShell. I’ve written over 35 PSMondays, and each has been shared with those that read this site, in addition to those with whom I work.

So, what’s in store for 2017? I’ll get back on the DSC train, but before I do, it’s time to put Pester under my belt in completion. I’m looking forward to The Pester Book by Don Jones and Adam Bertram. I like the idea of a reasonably priced book that’s well explained, as Don leads the way. Congratulations to Adam, however, as a collaboration project with Don has got to be exciting and rewarding. Don’s ability to explain the concepts, is up there at the top of PowerShell author elite.

Not PowerShell related, but I did buy a Python book this evening. I’d like to gain some more experience with Python, as well. As I was spending some time with it several month ago, I shared some simple examples with my then 9-year-old son. He’s seemed to catch on. I’ll be letting him read the book if he’s interested, as the book is actually intended for kids. What can I say, I’m intrigued. So I don’t feel so ridiculous, I will include this quotes from the page linked above: “An excellent introduction to programming for anyone interested in learning to program, regardless of their age.” 😉

Make some resolutions, too. It’s paying off for me, and it can help keep you on track. I’m still working toward the Hero and Microsoft MVP awards, both of which will give my work for the PowerShell community some vindication. Not that I don’t already know, I’ve been a help for some.

PSMonday #35: December 26, 2016

Topic: Foreach

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.

A day late, but here we go.

Like the If statement, the foreach statement is an often used language construct. In fact, I wouldn’t be surprised to find out that it was the second most used, right after the If statement. The foreach differs, however, in that it is a looping construct. This is to say that we use it to loop through a collection, or a group, of items.

As we’ve done in the past, let’s start with the conceptual format of the foreach construct. There’s always a few ways to write the same thing. The first part of this example, shows how it’s displayed in the PowerShell help, and the second part, is how I write, my foreach statements.

foreach ($<item> in $<collection>){<statement list>}

Foreach ($<item> in $<collection>) {
    <statement list>

The most common collection we’ll loop through using a foreach is an array. An array is a data structure, designed to store a collection of items. Before we get there, consider that many variables are only ever assigned a single value, such as in the below example.

$Computer = 'Server01'


In the previous example, the Computer variable only held a single, string value of “Server01.”

An array lets us get away with a single variable holding multiple values. Let’s start with the multiple values of ‘red’, ‘blue’, ‘green’, and ‘gray’. Each of these is an item, but together, they are a collection; they’re an array. Before we actually work with this array, we’ll assign it to the Colors variable. The decision to use a plural variable, is intentional.

$Colors = 'red','blue','green','gray'


With this variable set, we can loop through each item in the collection — each value in the variable — using foreach. The first time we enter the foreach, the Color variable (singular), will be ‘red.’ The second time we loop through, the Color variable is ‘blue.’ The third iteration into the foreach, it’s ‘green,’ and on the final pass, the Color variable is ‘gray.’

Foreach ($Color in $Colors) {
    Write-Output -InputObject "The `$Color variable is: $Color"

The $Color variable is: red
The $Color variable is: blue
The $Color variable is: green
The $Color variable is: gray

This item variable, could’ve been any word; however, we chose to use Color, because it made the most sense. The decision to use a single variable was intentional, too. Here’s the same example as above, however, we’ve changed Color to Hamburger. It makes no sense, but it still works.

Foreach ($Hamburger in $Colors) {
    Write-Output -InputObject "The `$Hamburger variable is: $Hamburger"

The $Hamburger variable is: red
The $Hamburger variable is: blue
The $Hamburger variable is: green
The $Hamburger variable is: gray

We’ll likely wrap up the foreach language construct next week, just in time to work with the ForEach-Object cmdlet. They’re different.

Use Foreach When it’s Really Needed

We’re not all the same, but if we were, and you were like me, you’d have a huge number of tabs open in your browser of choice. Each of them, would have some relation to PowerShell and each would be sitting by idle, and waiting to be read. No idea where it came from, but in one of them last week, I saw this:

Get-Date -Format o | foreach {$_ -replace ":", "."}

I stared at it for a moment, and thought, why is someone piping Get-Date to foreach? Get-Date only returns a single value. Why would that need to be handed off to a looping construct? The point here is, it wouldn’t need to be, even though it works. I’ve decided I should bring this up, in case someone else is potentially going to make this same mistake. Even if you’re a Systems Administrator, you’re still going to want to write efficient, and well thought out code. Here’s how I would have expected to see this written:

(Get-Date -Format o) -replace ":", "."

Again, Get-Date is only going to provide a single returned value, and therefore, we can trust that we don’t need to loop through a set of results. It’s cleaner code, it’s tighter code, and it gives the rest of us some confidence that you’ve thought things through.

One of the things I enjoying doing is testing the speed of various ways to do the same thing. Don’t think for a minute that I didn’t do that here. This next example indicates the time to run the foreach version of this Get-Date command. The second example, indicates the time to run when foreach is not used.

Milliseconds Ticks
------------ -----
           1 19094
           1 10543
           0  7044
           0  4212
           0  3944
           0  3849
           0  4133
           0  4349
           0  4099
           0  3948
Milliseconds Ticks
------------ -----
           1 12386
           0  5277
           0  4438
           0  2479
           0  2345
           0  2325
           0  4003
           0  2352
           0  2335
           0  2311

The times are close; they’re indistinguishable to us humans, but the numbers don’t lie. There’s a better way based both on time to complete, and competency. If you wanted to see it, here’s what I used to measure these two different commands. Keep these things in mind, and keep on learning!

1..10 | ForEach-Object {
    Measure-Command -Expression {
        Get-Date -Format o | foreach {$_ -replace ":", "."}
    } | Select-Object -Property Milliseconds,Ticks

1..10 | ForEach-Object {
    Measure-Command -Expression {
        (Get-Date -Format o) -replace ":", "."
    } | Select-Object -Property Milliseconds,Ticks