Cryptic PowerShell One-Liner to Clarified Script, Part 2

Finish the "prettifying" process

Mark Minasi

June 19, 2014

4 Min Read
Cryptic PowerShell One-Liner to Clarified Script, Part 2

Last month, in “Cryptic PowerShell One-Liner to Clarified Script, Part 1,” I began the process of converting a useful but cryptic one-liner into something prettier. This month, I’ll finish “prettyprinting” it, then provide another quick one-liner-to-script example. So far, I’ve used this:

get-aduser -filter * -properties * | foreach { set-aduser $_ -displayname ($_.givenname + " " + $_.sn)}

I started separating it into a multiline script by breaking the line at the pipeline (|), putting the result of the first line (get-aduser -filter * -properties *) into a variable (I used $Allusers, but any variable name would work) and used that variable to fill the pipeline for the operation on the right side of the pipeline (foreach …}, ending up with a mildly more readable two-line script:

$AllUsers= ( get-aduser -filter * -properties *)$AllUsers| foreach { set-aduser $_ -displayname ($_.givenname + " " + $_.sn)}

I also showed you that you can add a comment any time by typing an octothorpe (#) and that PowerShell will ignore any text to the right of that octothorpe. 

Now, let’s break the second line into multiple lines. The main component is a foreach-object cmdlet that has two shorter names, foreach or simply the percent sign (%).

Foreach’s syntax basically looks like

foreach { command; command; command… }

Pretty much whenever you see the braces (the {} symbols) in PowerShell, they typically enclose one or more PowerShell commands, separated by a semicolon: You’re seeing what PowerShell calls a scriptblock. PowerShell commands tend to be a bit verbose, so foreach scriptblocks can get long, which is why we’re knocking them down to size. Basically, we’ll simply start a line with foreach, put each cmdlet on a line of its own, then put the closing brace on a line by itself. We’ll also do some indenting to help readers keep track of which text is the scriptblock. That gives us our script, prettyprinted:

$AllUsers= ( get-aduser -filter * -properties *)$AllUsers|foreach {Set-aduser $_ -displayname ($_.givenname + " " + $_.sn)}

Notice how I use the braces. PowerShell needs to see the opening brace on the same line as foreach, although you can put it on a different line if you end foreach with a backtick, as in

foreach `                {                (commands)}

Also, this will work without the variable, so the script could look like

get-aduser -filter * -properties * |foreach {set-aduser $_ -displayname ($_.givenname + " " + $_.sn)}

Why the indenting? With a script this simple, it’s not all that essential. But if the script had a foreach inside of a foreach, it’d start getting difficult to follow without the indents, as in this prototype example:

get-something |foreach {                get-somethingelse |                foreach {                                Do something…                                Do something else…                                }                Do yet another thing…                }

You needn’t follow my formula exactly, but find an indenting style that works for you, or—I promise you—debugging or understanding any script beyond 10 lines will become impossible.

Here’s another example—one that’s trivial but might shine some light on how PowerShell works. Suppose you want to feed PowerShell a bunch of numbers in the pipeline and get their sum? It would look something like

2,77,13,92 | foreach { something using the $_ pipeline variable }

That should work for any arbitrary number of values in the pipeline, so you’ll need a variable to accumulate the sum. Call it $sum. Every time you loop through the pipeline, you can accumulate the sum with this command:

$sum = $sum + $_

$_ is the pipeline’s value, so that command should work. Here’s a first cut, then:

1,2,3 | foreach {$sum = $sum + $_}

Run that, and you’ll get … nothing. You never told PowerShell to display anything! Recall that simply typing the variable’s name causes PowerShell to display its value. Recall also that you can put more than one command on a line with a semicolon. So, you can next try this:

1,2,3 | foreach {$sum = $sum + $_} ; $sum

Run that, and you’ll get a result: 12. Wait, 12? What’s up with that? Ah, you never “initialized” the $sum value. The first time PowerShell ran across $sum=$sum+$_, it determined that it needed to create a numeric variable, and by default it started it off with the value zero. But after you run the script, the variable sticks around. Thus, the first time you ran the script, $sum started out as zero, but the second time, it started out with its previous value, 6. Let’s add one more command on the left side to initialize $sum:

$sum=0; 1,2,3 | foreach {$sum = $sum + $_} ; $sum

Now things work fine, and to finish off, let’s pretty it up:

$sum=01,2,3 |foreach {                $sum = $sum + $_                }$sum

I think you’ll agree that a multiline script is clearer to read than a humongous one-liner, and it’s easier to edit too. With the one-liner-to-script task out of the way, let’s go further and show PowerShell how to make decisions. Next month!

Sign up for the ITPro Today newsletter
Stay on top of the IT universe with commentary, news analysis, how-to's, and tips delivered to your inbox daily.

You May Also Like