Windows PowerShell Version 3 Simplified Syntax

Windows PowerShell version 3 introduces a simplified syntax for the Where-Object and Foreach-Object cmdlets.  The simplified syntax shown below, eliminates the curly braces as well as the need for the special variable $_.

The intent of this “syntax” is to make it easier for folks get started with PowerShell.  Compared to the commands below, I can see the value of the simplified syntax:

When folks are first learning PowerShell, the special variable $_ is one of those mental model hurdles they have to get over.  The simplified syntax feature of V3 seems to generate a fair amount of controversy (is it really necessary, doesn’t this just complicate things more, etc).  Regardless of where you stand on the simplified syntax it is useful to understand how it works.

Given that it appears to be a simplified expression syntax you might think this required a change to the PowerShell parser’s grammar but you would be wrong.  It turns out that the simplified syntax is implemented by additional parameter sets – lots of additional parameter sets. In fact, for every operator supported, there is an additional parameter set to support that operator.  Let’s see this with the Where-Object cmdlet by listing out all of its parameter set names:


Most of these correspond to the operators you are already familiar with such as: –GT, –LT, –GE, –LE, –LIKE, –MATCH, –NOTMATCH, –CONTAINS, –NOTCONTAINS, etc.  Note however there are two new operators in PowerShell V3: –In and –NotIn which you can use like so:

Let’s look at the interesting parameters on these operator specific parameter sets.  Let’s look at the EqualsSet parameter set:

As it turns out, these results are the same for all the operator oriented parameter sets.  At the very minimum, the Property parameter is required and is always the first positional parameter.  And as you would expect, if you don’t provide it, you get prompted for a value:

Now even though Value parameter is specified as not mandatory, in many cases if you don’t provide it you will get a terminating error e.g.:

There are some cases where you don’t have to provide the value nor the operator e.g.:

This works because A) the EqualsSet parameter set is the default parameter set and B) the Where-Object implementation appears to coerce the property specified (Responding in this case) to Boolean. If the result is $true then the object is output by Where-Object and sent on its way down the pipeline.

So all this simplified syntax really is, is a bunch of operator specific parameter sets on Where-Object that have a positional and mandatory Property parameter of type [string] and a positional Value parameter of type [object].  In the case of Foreach-Object it is one extra parameter set called PropertyAndMethodSet which has one mandatory, positional parameter called MemberName.  And as with any cmdlet, you provide the parameter values and the cmdlet determines how to interpret them.  In fact, given standard parameter parsing behavior the below is as valid as the conventional notation:

Now where this syntax can lead you astray if you don’t understand how it works, is if you make the assumption that this is a parsed expression.  In that case, folks might expect this to work:
There is a Threads collection on each Process object.  We might think that we can access a property on that collection but in effect, what happens is that the Where-Object Property parameter gets the value “Threads.Count” and there is no property on a Process object called “Threads.Count”. This silently fails which might lead you to believe there are no processes with greater than 100 threads.  But reverting back to the standard syntax we see that isn’t the case:
So when you are using the simplified syntax be sure to keep in mind that you can only specify property names and you cannot access sub-properties.  Keep your property names simple and you should be copasetic with the new, simplified syntax.  While I’m a little unsure about the new simplified syntax given how quickly you can fall off the “simple” path into the sharp rocks and lava below, I will say this.  As I wrote this blog post, I used the simplified syntax quite a bit and I have to say that it is growing on me.
One final item to mention about simplified syntax.  It turns out that some folks have a hard time grokking $_ but when they’re presented with $PSItem it apparently makes more sense to them.  So in PowerShell v3, wherever you can use $_ you can also use $PSItem$PSItem is not an alias. It seems to be a duplicate variable defined in all the same scopes as $_ and its value tracks that of $_ e.g.: