Select-Object worked the same inside and outside a % loop?! RRS feed

  • Question

  • I'm a bit mystified by a powershell output - it seems to have done what I meant, not what I said:

    First I loaded up a list of firstname/lastname lines from a CSV:

    $rlist = import-csv -path "c:\work\rlist.csv"

    Then I wasn't paying attention to where I put the "select" and placed it inside a loop:

    PS AD:\> $rlist | % {
    >>   $first = $_.first
    >>   $last = $_.last
    >>   get-aduser -filter { givenname -eq  $first -and surname -eq $last } | select samaccountname, name, enabled
    >> }

    which somehow gave me one line of headers, and several lines of samaccountame, name, enabled as I wanted, but didn't expect.

    as a sanity check, I tried the following, which gave the same output:

    PS AD:\> $rlist | % {
    >>   $first = $_.first
    >>   $last = $_.last
    >>   get-aduser -filter { givenname -eq  $first -and surname -eq $last }
    >> } | select samaccountname, name, enabled

    I've read other forum posts exhorting PowerShell users to make sure the select-object is outside any loops to avoid duplicate headers, so I'm mystified how the first one did NOT duplicate headers?

    Monday, January 28, 2019 6:46 PM

All replies

  • Powershell does a lot of output optimization under the hood for you without forcing you to ask for it. You should be glad about that!  ;-) :-D

    Live long and prosper!


    Monday, January 28, 2019 6:55 PM
  • It's not really outputting text.  It's outputting objects, and then formatting it as text for the console.  In the end, the result is the same.

    Monday, January 28, 2019 6:57 PM
  • It's not really outputting text.  It's outputting objects, and then formatting it as text for the console.  In the end, the result is the same.

    This is normal.  Select-Object works both ways.  The difference is that the output of the ForEach loop is full objects when the select-object is outside the loop and the objects only have the properties selected when the select is inside the loop.  Normally, for performance and usability we put the select outside the loop.


    Monday, January 28, 2019 7:04 PM
  • Here is an example:

    PS D:\scripts> Get-ChildItem | %{ $_ | select name } | select -first 5
    PS D:\scripts> Get-ChildItem | %{ $_  } | select -first 5
        Directory: D:\scripts
    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----        6/26/2017   6:59 PM                bin
    d-----        3/15/2017   3:42 PM                BurntToast
    d-----        6/19/2018   3:39 AM                devcon
    d-----        12/7/2018  10:31 AM                DeviceManagement
    d-----        8/17/2018   1:19 PM                en-US

    Note when outside the loop all properties are returned.

    Also note that the inner select creates a new object (pscustomobject) and strips all methods from  the objects making the objects less useful in the pipeline.

    PS D:\scripts> Get-ChildItem | %{ $_ | select name } | select -first 5|gm
       TypeName: Selected.System.Management.Automation.PSCustomObject
    Name        MemberType   Definition
    ----        ----------   ----------
    Equals      Method       bool Equals(System.Object obj)
    GetHashCode Method       int GetHashCode()
    GetType     Method       type GetType()
    ToString    Method       string ToString()
    Name        NoteProperty string Name=bin
    PS D:\scripts> Get-ChildItem | %{ $_  } | select -first 5|gm
       TypeName: System.IO.DirectoryInfo
    Name                      MemberType     Definition
    ----                      ----------     ----------
    LinkType                  CodeProperty   System.String LinkType{get=GetLinkType;}
    Mode                      CodeProperty   System.String Mode{get=Mode;}
    Target                    CodeProperty   System.Collections.Generic.IEnumerable`1[[System.String, mscorlib, Version=, Culture=neutral, PublicKeyToken
    Create                    Method         void Create(), void Create(System.Security.AccessControl.DirectorySecurity directorySecurity)
    CreateObjRef              Method         System.Runtime.Remoting.ObjRef CreateObjRef(type requestedType)
    CreateSubdirectory        Method         System.IO.DirectoryInfo CreateSubdirectory(string path), System.IO.DirectoryInfo CreateSubdirectory(string path, Sy
    Delete                    Method         void Delete(), void Delete(bool recursive)
    EnumerateDirectories      Method         System.Collections.Generic.IEnumerable[System.IO.DirectoryInfo] EnumerateDirectories(), System.Collections.Generic.
    EnumerateFiles            Method         System.Collections.Generic.IEnumerable[System.IO.FileInfo] EnumerateFiles(), System.Collections.Generic.IEnumerable
    EnumerateFileSystemInfos  Method         System.Collections.Generic.IEnumerable[System.IO.FileSystemInfo] EnumerateFileSystemInfos(), System.Collections.Gen
    Equals                    Method         bool Equals(System.Object obj)
    GetAccessControl          Method         System.Security.AccessControl.DirectorySecurity GetAccessControl(), System.Security.AccessControl.DirectorySecurity
    GetDirectories            Method         System.IO.DirectoryInfo[] GetDirectories(), System.IO.DirectoryInfo[] GetDirectories(string searchPattern), System.
    GetFiles                  Method         System.IO.FileInfo[] GetFiles(string searchPattern), System.IO.FileInfo[] GetFiles(string searchPattern, System.IO.
    GetFileSystemInfos        Method         System.IO.FileSystemInfo[] GetFileSystemInfos(string searchPattern), System.IO.FileSystemInfo[] GetFileSystemInfos(
    GetHashCode               Method         int GetHashCode()
    GetLifetimeService        Method         System.Object GetLifetimeService()


    • Edited by jrv Monday, January 28, 2019 7:09 PM
    Monday, January 28, 2019 7:08 PM