Select –ExpandProperty <PropertyName>

Select –ExpandProperty <PropertyName>

  • Comments 10

Most of us are familiar with the traditional use of Select –ExpandProperty <propertyname>.  This takes a the value of an incoming object, enumerates its values and outputs each of those values as a single record on the output stream after adding any properties specified by the –PROPERTIES <propertyname[]> parameter.  An example will help:

PS> gps |Select -ExpandProperty Modules -ea SilentlyContinue |Group ModuleName |Sort Count |Select -Last 4

Count Name                      Group
----- ----                      -----
   58 kernel32.dll              {System.Diagnostics.ProcessModule (kernel32....
   58 msvcrt.dll                {System.Diagnostics.ProcessModule (msvcrt.dl...
   58 KERNELBASE.dll            {System.Diagnostics.ProcessModule (KERNELBAS...
   72 ntdll.dll                 {System.Diagnostics.ProcessModule (ntdll.dll...

 

 

A while ago, Lee Holmes turned me on to another use of –ExpandProperty and I’ve been meaning to blog it ever since.  Have you ever wanted to get just the value for a property from every object?  You’d think you could do this and it would work:

PS> gps *ss |select name

Name
----
csrss
csrss
lsass
smss

 

Sadly, this is not what you want. This gives you a set of objects each of which has exactly one property:  NAME.  What you wanted was a stream of VALUES.  What I’ve always ended up doing was this:

 

PS> gps *ss | foreach {$_.Name}
csrss
csrss
lsass
smss

 

 

This works, it is not too hard but it always sorta pissed me off that I had to do it this way.  Sadly, addressing this never made it above the cut like for V2.  Again – to ship is the choose.  I was complaining about this one day and Lee pointed out that if you specify a scalar property (a property that is NOT a collection) for –ExpandProperty – it gives you exactly what you want.

PS> gps *ss |select -ExpandProperty name
csrss
csrss
lsass
smss

 

SWEET!

Enjoy!

Jeffrey Snover [MSFT]
Distinguished Engineer
Visit the Windows PowerShell Team blog at:    http://blogs.msdn.com/PowerShell
Visit the Windows PowerShell ScriptCenter at:  http://www.microsoft.com/technet/scriptcenter/hubs/msh.mspx

Leave a Comment
  • Please add 4 and 2 and type the answer here:
  • Post
  • Awesome, thanks Jeffrey!  

    I always look forward to these posts and am working to drive PowerShell adoption at my company.   Your prior post on "Quick and Dirty Scripting" was right on.  I spend my day trying to make the shortest most flexible (and valuable) scripts to keep my admin time minimal.   We all appreciate your hard work to automate admin work here.

  • Haha.  I always hate having the foreach loop too.   You guys have too many features in Powershell that I find out on this blog and not while using it :)

    Thanks for the post.

  • Why is this an improvement? It's more characters to type (than %{$_.Name}).

  • @Dave - because of tab-completion

    jps

  • When I try that final command, I get this error:

    Select-Object : Cannot expand property "name" because it has nothing to expand.

    At line:1 char:16

    + gps *ss |select  <<<< -ExpandProperty name

  • That sounds like the TypeExpansion files didn't load during startup.  Try using Processname instead.

    Then figure out why you are missing the type expansion stuff.  make sure the file exists:

    test-path $pshome/types.ps1xml

    then update the data:

    Update-TypeData $pshome/types.ps1xml

    and try it again with "NAME".

    jps

  • I was writing a one liner to list all the verbs in the builtin cmdlets and ended up using foreach. I, too, was annoyed by having to use foreach instead of select. In reflecting on my annoyance, I think it is because at first glance foreach seems like it should execute a "for loop" for every item that comes through the pipeline - in essence double nested iteration. Which intuitively seems excessive.

    However I realized that a "for loop" is probably not executed for every item in the pipeline, but a single iteration of the "for loop" occurs for each instance in the pipeline. (At least I hope that's what happens.)

    From this it occured to me that really the problem is with the ingrained expectation of a statement called "foreach". As a C programmer I'd expect something named "for" followed by a body to perform a whole set of iterations each time it is "entered". But in Powershell the "for loop" only does one iteration for each time it is "entered". The difference between a traditional "for" and PS foreach is that the iteration specification is syntactically outside of the for statement instead of within it. So you have to think of "for each" as applying to the pipeline as a whole instead of to an individual command in the pipeline.

    Maybe names like "WithEachDo" or "AsEachItemPassesDo" better reflects how the foreach command is a stage in a pipeline.

  • Each object is passed along the Pipeline together with it's properties. A foreach in this case, where there is an object with mutiple properties being pipelined, will actually mean foreach Property ( foreach object inside the object), and not foreach Object. It makes sense and there is no need for a WithEachDo.

  • I was studying powershell and one example used select -expandproperty on a single string, the book didn't explain more why it used -expandproperty. I read below one of guys had an error which I exactly expected using -expandproperty on single string property. My question is why we have to use -expandproperty to get the list of single property of each object, and using that also reduces the processing load instead of just using 'select name'? In other words, does 'select -expandproperty' against a single string property of object through pipeline reduce going through the stream of multiple objects than just simply selecting it's property?

  • I disagree with this approach. I prefer the foreach method. To me, it's actually clearer what's happening, and it gives me more control if I want to customize.

Page 1 of 1 (10 items)