Last month, in "Going Further with ForEach," I showed you how to recast any Active Directory (AD) one-liner into a mildly more complex form based on the pipeline variable $_ and PowerShell's ForEach command to enable more flexibility. This month, I'll show you a less trivial ForEach example and assemble it in "slow motion" to help clarify how you can build your own one-liners.

I started this discussion about ForEach-based one-liners by offering this simple but non-trivial task: Assuming your AD accounts contain a givenname (the AD attribute for "first name") and sn ("last name"), you can clean up your DisplayName values by simply concatenating each account's givenname with a space and then its sn, resulting in a pretty good set of DisplayNames.

A side note: Before you ask me why Microsoft used givenname for "first name" but shortened "surname" to sn, let me say that it wasn't Microsoft's fault. The company based AD's schema on the X.500 schema. X.500 was intended to be a template for any communications service that required usernames and passwords, and the work on its structure and attribute names began back in 1984. When you realize that another of X.500's standard user attributes was FavoriteBeverage, it's easy to guess that, well, maybe givenname was defined before a lunch break that included favorite beverages, and that sn was defined later in the afternoon. I should also mention that the AD team at Microsoft took pity on us and added a "synthetic" extra attribute called surname that only PowerShell knows. The surname attribute is really just an alias for sn—much more aesthetic, I think you'll agree.

As always, it's easiest to design this one-liner from a high level down by determining the "filter" (which accounts to modify) and the "hammer" (what to do to them). In this sample filter, you want to perform this action on all AD accounts, so the filter is easy:

get-aduser -filter * -properties *

Next, you'll want to modify the DisplayName attributes of those accounts. The generic cmdlet for tweaking an AD user's attribute is, as you've seen so far, Set-ADUser. Now, assembling its syntax will be a little more complex than for Get-ADUser, so let's start by reviewing a simple example of Set-ADUser. To set a user with the samaccountname "john" to a DisplayName of "John Smith," the syntax would look like

set-aduser john -displayname "John Smith"

Next, let's assemble the entire one-liner along the lines laid out last month:

get-aduser -filter * -properties * | foreach {do something that uses $_}

Your next job is to take that static Set-ADUser example above, along with the pipeline variable $_, and see if you can write whatever goes into {do something that uses $_}. I do this by recasting that Set-ADUser example to make it more generic, but in English:

set-aduser [logon name of the current user in the pipeline] -displayname (user's givenname, concatenated to a space, concatenated to the sn of the user in the pipeline)

I put the parentheses around the last part for two reasons. First, it's a nice way of clarifying what you need to figure out syntax-wise and, second, putting them in the final one-liner will make it a bit more readable to someone trying to figure out six months from now what this does and how it does it. (Trust me, more often than not, that someone will be you.)

Recall that concatenate in PowerShell is just the plus sign, and of course a space is just a blank character surrounded by quotes. So, that simplifies my Set-ADUser command to

set-aduser [logon name of the current user in the pipeline] -displayname (user's givenname + " " + user's sn)

The final part of converting this into PowerShell-ese is to describe the user's logon name, givenname, and sn, which are all attributes of the current object in the pipeline, $_. The Set-ADUser command then looks like

set-aduser $_.samaccountname -displayname ($_.givenname + " " + $_.sn)

Even better, a bit of messing with Set-ADUser shows that it doesn't need to be directed to the samaccountname attribute, because it's smart enough to get past the whole object and function properly. Put that Set-ADUser command into the scriptblock for ForEach, and you get

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

It's not quite as clear as the simple non-ForEach one-liners you've built so far, but it gets a lot done. If it were only a little easier to read, right? Join me next month, and I'll clarify things a bit.