Windows PowerShell : New Syntax in the New Shell

Some new syntax commands in Windows PowerShell version 3 help you write easier-to-read, but somewhat limited, commands.

Don Jones

One of the new features in Windows PowerShell version 3 is a new form of syntax for the Where-Object and ForEach-Object cmdlets. Both of these cmdlets normally accept a scriptblock (in the case of Where-Object, it’s called a filterscript, because it must return either $True or $False).

Within that scriptblock, you use the $_ placeholder symbol to represent “whatever was piped in to the cmdlet.” Here’s an example using both cmdlets (this isn’t a sensible real-world command, but it demonstrates the use of the cmdlets):

Get-WmiObject –class Win32_LogicalDisk | Where-Object –filterscript{ $_.DriveType –eq 3 } | ForEach-Object –process { $_.ChkDsk() }

You never see these commands written out this way. People tend to use aliases, truncated parameter names and positional parameters to save typing. The following isn’t unusual:

gwmi Win32_LogicalDisk | ? { $_.DriveType –eq 3 } | % { $_.ChkDsk() }

There’s nothing like a little arcane syntax to ensure job security, right? Where-Object’s new syntax lets you do this:

gwmi Win32_LogicalDisk | where DriveType –eq 3 | % { $_.ChkDsk() }

Notice I switched to a different alias for the cmdlet. You can still use ? if you want, but that drives me crazy. I come from a long BASIC background, where ? was a shortcut for the Print statement. Reading ? in a Windows PowerShell command hurts my brain. I’ve also dispensed with the curly brackets and the $_ symbol.

Essentially, Where-Object now has a positional parameter to accept the property you want to filter on (DriveType, in my example). It defines all the main Windows PowerShell operators (-eq, -ne, -like, -gt and so forth) as parameters. The value for that parameter is the value you want to filter for (here, the value is 3). This shortened form is easier to read, but you can only use it for a single comparison. For example, the following isn’t a legal statement:

Gwmi Win32_Service | Where StartMode –eq 'Auto' –and State –ne 'Running'

For that, you’ll have to switch back to the old-school syntax:

Gwmi Win32_Service | Where { $_.StartMode –eq 'Auto' –and $_.State –ne 'Running' }

ForEach-Object gets a similar, reduced-punctuation syntax form:

gwmi Win32_LogicalDisk | where DriveType –eq 3 | foreachChkDsk()

Again, I’ve switched to the ForEach alias instead of % to make this easier to read. You could continue using % if you like. One of my fellow MVPs wrote a great blog article about these shortened forms, and it’s worth a read. He also introduces $PSItem, which seems to be an alternate for the often misunderstood $_ symbol.

Personally, I have mixed feelings about these new syntax forms. On the one hand, they’re definitely easier for a newcomer to grasp. Eliminating the curly brackets and the always confusing $_ is great. On the other hand, these new forms aren’t fully functional. They can only do a single comparison. You’ll still need to learn the old syntax.

Also, there are more than six years of old-style syntax floating around in people’s blogs, magazine articles and books. You’re still going to need to know the old syntax in order to make sense of those examples.

So this new syntax doesn’t eliminate the need to know the old syntax. It just means you have two forms to remember instead of one. Nevertheless, it’s what we have to work with, so that’s the way we’ll work.

Don Jones

Don Jones  is a Microsoft MVP Award recipient and author of “Learn Windows PowerShell in a Month of Lunches” (Manning Publications, 2011), a book designed to help any administrator become effective with Windows PowerShell. Jones also offers public and on-site Windows PowerShell training. Contact him through ConcentratedTech.com or bit.ly/AskDon.