locked
Select-Object returning selected PSCustomobject instead of selected type RRS feed

  • Question

  • Hello,

    I've asked this question at powershell.org as well

    https://powershell.org/forums/topic/retain-type-when-using-select-object/#post-231241

    When I am looking at objects and pipe to Select * - they seem to always have type of 'selected dot whatever the original type' was. When I do the same with modules from the PSGallery, they come back as PSCustomObject and are no longer able to be piped into install-module. Like I said there, I understand I can work around it but it seems like either the select-object cmdlet or powershellget provider is not doing something correctly. I found some articles online that discuss similar questions, but they are actually selecting custom properties making a custom object. I'm just wanting all members of the object. I appreciate any input. 

    This works fine

    Find-Module -Name *somemodule* | install-module
    
    Find-Module -Name *somemodule* | install-module

    This fails

    Find-Module -Name *somemodule* | select * | install-module Install-Module : Invalid value is specified for InputObject parameter.

    Find-module -Name a* | get-member
    
        TypeName: Microsoft.PowerShell.Commands.PSRepositoryItemInfo
    
    Find-Module -name a* |select -first 1 -Property * | get-member
    
        TypeName: Selected.System.Management.Automation.PSCustomObject

    Which is to blame?

    Wednesday, May 27, 2020 4:12 AM

Answers

  • Appears to be fixed in PowerShellGet 3.0 Preview 3. This works:

    PS C:\> Find-PSResource PSDiscoveryProtocol | select -First 1 -Property * | Install-PSResource

    • Marked as answer by DMaurer Thursday, May 28, 2020 2:19 AM
    Wednesday, May 27, 2020 9:24 PM

All replies

  • The only question to ask is why would you do that?

    Select-Object returns a custom object always.  The repository CmdLets can't be used like that.  They require the actual module and not a listing of the properties.

    Take some time to read the documentation on how the pipeline works and decide what teh CmdLets are doing.


    \_(ツ)_/

    Wednesday, May 27, 2020 11:06 AM
  • I’ve explained why on the other thread and I’ve shown it works with all other core cmdlets and custom modules as well such as dbatools and importexcel. If you don’t know why this one behaves differently than the rest, perhaps let someone else answer?
    Wednesday, May 27, 2020 2:53 PM
  • I may be wrong, but:

    The underlying object type returned by Find-Module is "Microsoft.PowerShell.Commands.PSRepositoryItemInfo".

    The type returned by Select-Object is "Selected.System.Management.Automation.PSCustomObject".

    Offhand, I'd say the documentation for the Install-Module is incorrect (or misleading) since it states that the -InputObject expects a "PSObject[]" type. It also says that the -Name parameter accepts pipeline input ByPropertyName and the "Select-Object *" produces a PSCustomObject that has a "Name" property.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Wednesday, May 27, 2020 3:19 PM
  • You need to understand what happens to an object when it is serialized and then extracted.  In your case there is no reason to do what you are doing.  If you are installing then there is no pointing in rebuilding the module into a custom object which will strip citical bits from the module and it will not work when sent back to the remote.

    Read the documents for the Install-Module to see what properties it requires.  Do these properties exist on the module reference returned or does the command use the module type to determine what to look for.


    \_(ツ)_/

    Wednesday, May 27, 2020 4:42 PM
  • I may be wrong, but:

    The underlying object type returned by Find-Module is "Microsoft.PowerShell.Commands.PSRepositoryItemInfo".

    The type returned by Select-Object is "Selected.System.Management.Automation.PSCustomObject".

    Offhand, I'd say the documentation for the Install-Module is incorrect (or misleading) since it states that the -InputObject expects a "PSObject[]" type. It also says that the -Name parameter accepts pipeline input ByPropertyName and the "Select-Object *" produces a PSCustomObject that has a "Name" property.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Just a note - the PsObject[] indicates a limited explanation.  It is a PsObject[] of Microsoft.PowerShell.Commands.PSRepositoryItemInfo

    When we use select-object we create a PsObject[] of PsCustomObject.  The object type is now gone.  Internally the command is looking for the type.

    Some commands are more flexible and are not as type restricted. As I noted above - there is no reason to use Select-Object in this way or with thesemands.


    \_(ツ)_/

    Wednesday, May 27, 2020 4:47 PM
  • I'll add the information I posted at powershell.org.Out of all the tests I've done so far, all objects that pass through Select-Object are returned as selected.original.type except for modules.

    Get-Process | select -First 1 -property * | gm
    
       TypeName: Selected.System.Diagnostics.Process
    
    Get-Service | select * | gm
    
       TypeName: Selected.System.ServiceProcess.ServiceController
    
    Get-ChildItem -File | select -First 1 -property * | gm
    
       TypeName: Selected.System.IO.FileInfo
    
    Get-Item C:\Windows | select * | gm
    
       TypeName: Selected.System.IO.DirectoryInfo
    
    Get-Command -Verb start | select -first 1 -property * | gm
    
       TypeName: Selected.System.Management.Automation.AliasInfo
    
    Get-Acl -Path C:\Windows | select * | gm
    
       TypeName: Selected.System.Security.AccessControl.DirectorySecurity
    
    get-date | select -Property * | gm
    
       TypeName: Selected.System.DateTime
    
    Get-WindowsCapability -Name rsat.act* -Online | select * | gm
    
       TypeName: Selected.Microsoft.Dism.Commands.AdvancedCapabilityObject
    

    To answer the question as to why anyone would want to pass an object with more/less/other than it's default members (for some reason that's a question) down the pipeline.

    $modules = Find-Module -Name "*$searchterm*" | 
        select-object * | Out-Gridview -Title "Select the module(s) you want to install" -passthru
    

    The reason this even came up is trying to give the user more info to choose which module(s) to install. This is just an example, the actual command select specific properties but the effect is the same. For keeping it small/simple in the forum, I just put Select *. Regardless of why someone would want to do this, the question actually is, why does this behave differently than others.

    Get-Service bits | select * | Stop-Service -whatif                                              What if: Performing the operation "Stop-Service" on target "Background Intelligent Transfer Service (bits)".
    
    get-date | select * | Set-Date -WhatIf
    What if: Performing the operation "Set-Date" on target "2020-05-27 12:00:00 AM".
    
    get-process wordpad | select * | Stop-Process -WhatIf
    What if: Performing the operation "Stop-Process" on target "wordpad (9944)"

    I don't believe this is a dumb question and for sure I feel the condescending notion of JRV to "read the documentation to learn how the pipeline works and decide what the cmdlets are doing" was unfounded and uncalled for. Clearly the pipeline works for these examples, where the same action with Find-Module | select-object does not. Are these examples not functioning as intended/designed? That's what is being suggested. It seems to me the issue here isn't my lack of understanding of powershell/pipleine/cmdlets - it's the inconsistent behavior in powershell that I am highlighting.

    Thanks for your time responding Rich. I also commented on the help for Install-Module being quite unhelpful. It takes a Microsoft.PowerShell.Commands.PSRepositoryItemInfo which is shown online, alongside System.Management.Automation.PSobject. The built in help only shows PSGetItemInfo. Certainly this is why the parameter binding fails. The remaining question is why does Select-Object return generic PSCustomObject for this one type? (could be more, i'm looking)

    Wednesday, May 27, 2020 4:58 PM
  • Objects returned from Find-Module are wrapped in a PsCustomObject but are of the correct type.  When you "select" them you are messing up this wrapper.  You are unwrapping it and then creating a new object with the properties of the old object.

    Again.  There is no reason to do this.


    \_(ツ)_/

    Wednesday, May 27, 2020 5:03 PM
  • Again there is a reason to do this. I want to select and display a property that doesn't show by default. When I do, it messes up the wrapper, not me. Have you looked at the many examples where this "select" action doesn't mess up the wrapper? You are insisting the behavior in those examples is improper, and the proper one is the module behavior?
    Wednesday, May 27, 2020 5:22 PM
  • Again there is a reason to do this. I want to select and display a property that doesn't show by default. When I do, it messes up the wrapper, not me. Have you looked at the many examples where this "select" action doesn't mess up the wrapper? You are insisting the behavior in those examples is improper, and the proper one is the module behavior?

    That is not what your code is doing.

    Find-Module SqlServer | 
        Foreach-Object{
            $_|select Name
            $_|Install-Module -WhatIf
        }

    Without some real-world code then your question is pointless.


    \_(ツ)_/

    Wednesday, May 27, 2020 5:33 PM
  • Again there is a reason to do this. I want to select and display a property that doesn't show by default. When I do, it messes up the wrapper, not me. Have you looked at the many examples where this "select" action doesn't mess up the wrapper? You are insisting the behavior in those examples is improper, and the proper one is the module behavior?

    That is not what your code is doing.

    Find-Module SqlServer | 
        Foreach-Object{
            $_|select Name
            $_|Install-Module -WhatIf
        }

    Without some real-world code then your question is pointless.


    \_(ツ)_/

    I really don't understand your combative position. Clearly Powershell is operating in an inconsistent manner, as demonstrated, yet you seem to ignore that and only focus on my intentions as well as assume I'm just another simpleton who hasn't spent any time with powershell. It's clear you did not read the post from powershell.org, why even comment? I understand I can work around this, as stated here and at powershell.org. I'm just looking for any insight as to why this is the case and if I should submit an issue on either powershellget or Select-Object, as this seems to be broken. Here is a real-world example, I sure hope it allows us to move past this point and on to the inconsistent behavior.

    # This works
    Get-service | Select-Object -Property name,requiredservices,status,starttype | Out-GridView -PassThru | Stop-Service
    
    # This works
    get-process | select * | Out-GridView -PassThru | Stop-Process
    
    # This works
    $searchterm = Read-Host -Prompt "Enter partial or complete module name" 
    Find-Module -Repository PSGallery -Name "*$searchterm*" | Out-GridView -Title "Choose the module(s) you would like to install" -PassThru | install-module -Scope CurrentUser
    
    # This does not work
    $searchterm = Read-Host -Prompt "Enter partial or complete module name" 
    Find-Module -Repository PSGallery -Name "*$searchterm*" | select version,Name,Author,description,projecturi,repository | Out-GridView -Title "Choose the module(s) you would like to install" -PassThru | install-module -Scope CurrentUser
    
    # The error
    install-module : Invalid value is specified for InputObject parameter.
    At line:1 char:203
    + ...  would like to install" -PassThru | install-module -Scope CurrentUser
    +                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (@{Version=2.0.2...tory=PSGallery}:PSObject) [Install-Module], ArgumentException
        + FullyQualifiedErrorId : InvalidInputObjectValue,Install-Module

    Wednesday, May 27, 2020 6:07 PM
  • I wasn't arguing that there was any need to do anything. Please don't put words in my mouth. I was saying that the help for the command is misleading. If the input from the  pipeline must be of a specific type, why not just say so?

    If you saw this in another cmdlet's help, and piped a PSCustomObject with a NoteProperty named "Name" would you not expect it to work?

    -Name

      Specifies the exact names of modules to install from the online gallery.
      A comma-separated list of module names is accepted. The module name must
      match the module name in the repository. Use Find-Module to get a list
      of module names.

      Type: String[]
      "">  Default value: None
      Accept pipeline input: True (ByPropertyName)
      Accept wildcard characters: False


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)


    Wednesday, May 27, 2020 7:09 PM
  • Yes Rich, 100% agree. I would expect it to accept a generic object with the name noteproperty. Furthermore in the case I am making here, I 110% expect it to take the very object it accepts properly when passed with the default properties. It is not a custom object as JRV suggests, it is the very object that Install-Module is expecting as it goes into select-object. The issue at hand is the Type being destroyed when it seems it should not be, as supported by the identical procedure used with output from other cmdlets. It's the original object, simply adding more than the default properties to it. Regardless, the examples of the other cmdlets output used in the same manner, work as one (I especially) would expect it to. Only in the case (so far) of the Find-Module output does this issue occur. I guess I'll just submit an issue for both powershellget and Select-Object... I just thought someone might have already experienced it before and had an explanation or possibly other examples where this same issue occurs. Thank you very much for your time, Rich.
    • Edited by DMaurer Wednesday, May 27, 2020 7:59 PM
    Wednesday, May 27, 2020 7:59 PM
  • Hah!  It seems that we have a major disconnect of understadning.

    Rich is correct and is pointing at how this works at one level.  On the other hand "Dmaurer" is arguing that there is something wrong based on a misunderstanding of how PowerShell works.  I, on the other hand, am trying to point out that this behavior is normal and when used in a pipeline it works correctly if you don't rebuild the object.  The cause is that the "Import-Module" command assumes a specific object or a string.  When it receives an object it treats it as a PsObject array and attempts to extract a PSRepositoryItemInfo object.  If you convert this using Select-Object it will fail.

    Rich notes that the pipeline input is by property name except that it also accepts strings of names that are not properties.

    The reason this is so hard to see is the following definition:

    -InputObject <PSObject[]>
        Used for pipeline input.
    
        Required?                    true
        Position?                    0
        Default value                None
        Accept pipeline input?       True (ByPropertyName, ByValue)
        Accept wildcard characters?  false

    Note that pipeline input is by both property name and value.  By value gets you strings names.  By ProeprtyName gets you the property of the PsCustomObject wrapper that is the PSRepositoryItemInfo object.   When you run it through Select-Object this is removed.

    This is a behavior of the pipeline that affects many types of objects and always causes surprise.  When we return a DataTable object from a function the data table is removed and we get only the row set.  TO successfully return a data table we need to wrap it in an object array of some type with a null first entry. The array is stripped in the pipeline and the null is discarded and now we have our data table or tables.

    It took me almost a year to get comfortable with this behavior.  I still do not have a clear understanding of what kinds of class definitions cause this.  One day I will try to track it down now that the source code for many of these objects is available on GitHub.

    When we use this code correctly the issue never presents itself as teh code I posted above demonstrates.  There is never a need to place a select-Object in THIS pipeline.  Compatibility with the pipeline is up to the guys generat9ing pipeline output.  To that end realize that commands for Exchange and Azure very often behave like this.  When you pipeline them without realizing that you are working with deserialized collections things like this happen.

    This is why I objected to the issue of using this pipeline construction as given in the OP's original example.  This is not combative it is just me trying to get you to rethink your issue and see that it is not an issue.  It is one thing you need to know about PowerShell and it does not indicate that there is any issue.  Your usage is not an intended usage and there is no time where you would need to do this.


    \_(ツ)_/

    Wednesday, May 27, 2020 8:05 PM
  • You need to understand what happens to an object when it is serialized and then extracted.  In your case there is no reason to do what you are doing.  If you are installing then there is no pointing in rebuilding the module into a custom object which will strip citical bits from the module and it will not work when sent back to the remote.

    Read the documents for the Install-Module to see what properties it requires.  Do these properties exist on the module reference returned or does the command use the module type to determine what to look for.


    \_(ツ)_/

    Are you even reading any of this? Why on Earth would a perfectly acceptable object that obviously includes the correct properties lose these properties with | Select * ?? I'll give you the TL;DR since it seems that's what you're all about.

    1. Object returned from Find-Module can be piped into Install-Module.

    2. Same object with all properties added to it with Select-Object can't be piped into Install-Module.

    3. It is obvious the issue is with the Type returned by Select-Object, as stated.

    4. Other objects (many of them) undergoing the same procedure (adding all properties with Select-Object, in case you forgot already) are emitted with type of Selected.Original.Type continue to be accepted as pipeline input as expected.

    End of TL;DR

    If the issue was that the Install-Module command did not accept Selected.Microsoft.Powershell.Commands.PSRepositoryItemInfo... that would be one thing. But the actual thing seems to be, for some reason (the goal of my post,) Select-Object outputs a generic PSCustomObject type. Again, based on the testing of other cmdlets/objects, it appears this is a problem.

    I have read your answers for years, JRV, and used to think very highly of you.

    Wednesday, May 27, 2020 8:13 PM
  • Interesting find, and this behaviour is still present in PowerShell 7.0.1.

    PS C:\> Find-Module PSDiscoveryProtocol | select -First 1 -Property * | Install-Module
    Install-Module: Invalid value is specified for InputObject parameter.
    PS C:\> Find-Module PSDiscoveryProtocol | select -First 1 | Install-Module
    Both of the above will return a PSCustomObject, and I have not found any difference between the two objects, yet only the last one work.

    Wednesday, May 27, 2020 9:02 PM
  • Point is that the definition does not allow objects to be accepted by name when the object is not of the proper type.

    If you really think this is a bug then this is not the place to register it.  We have "UserVoice" as the place to register bugs in PowerShell.  Post there to get their take on this.  They will run it by the developers.  I suspect they will also note that hen a PsObject arrives at the pipeline door that it will be inspected for type and rejected if it is not the type expected.  After accepting a correct type then the "Name" property will be bound and any other bindable property will be bound.

    I think the disconnect here is that you are making an assumption from the outside of the code binding methodology and that the inside view explains.

    Rich has a point in that the documentation, as is often the case, is a bit misleading.

    In coding we have a view that behaviors that do not disrupt use or alter outcomes are not an issue.  They can be an issue when someone uses code in a non-standard way.  Is the use wrong?  That depends.  Your example is a non-starter because there is no case where anyone would do what you are doing.  Does this make the pipeline more challenging to use with this CmdLet?  Yes.  This is the same with Exchange and Azure CmdLets.  The common element is that they are all remote commands and they are commands that deserialize their payload into objects that have behaviors that do not allow them to be marshalled remotely.  You cannot send a rebuilt object back to the repository.  It is the repository that is likely the part complaining.  It expects a copy of the fulll unmodified deserialized object.

    This kind of thing happens everywhere we use a pipeline with direct remoting.  


    \_(ツ)_/

    Wednesday, May 27, 2020 9:10 PM

  • Are you even reading any of this? Why on Earth would a perfectly acceptable object that obviously includes the correct properties lose these properties with | Select * ?? I'll give you the TL;DR since it seems that's what you're all about.


    My point is that the object type has changed and the object type is required for the remote call.  Select-Object removes the object type.

    Carefully read the error message returned:

    PS C:\scripts> [pscustomobject]@{Name='SQLServer'} | install-module  -WhatIf
    install-module : Invalid value is specified for InputObject parameter.
    At line:1 char:39
    + [pscustomobject]@{Name='SQLServer'} | install-module  -WhatIf
    Notice that it sees the object type first and not the property.  That is what the documentation is trying to tell us.  Again- the docs are confusing with this case.


    \_(ツ)_/

    Wednesday, May 27, 2020 9:16 PM
  • Interesting find, and this behaviour is still present in PowerShell 7.0.1.

    PS C:\> Find-Module PSDiscoveryProtocol | select -First 1 -Property * | Install-Module
    Install-Module: Invalid value is specified for InputObject parameter.
    PS C:\> Find-Module PSDiscoveryProtocol | select -First 1 | Install-Module
    Both of the above will return a PSCustomObject, and I have not found any difference between the two objects, yet only the last one work.

    I have addressed this many points above.  It is by design and 7 will behave exactly the same way.  You can pull the source code to dig deeper into how this works.


    \_(ツ)_/

    Wednesday, May 27, 2020 9:18 PM
  • Appears to be fixed in PowerShellGet 3.0 Preview 3. This works:

    PS C:\> Find-PSResource PSDiscoveryProtocol | select -First 1 -Property * | Install-PSResource

    • Marked as answer by DMaurer Thursday, May 28, 2020 2:19 AM
    Wednesday, May 27, 2020 9:24 PM
  • Your first example picks the first object through the pipeline and passes it (intact) down the pipeline. That object retains its type ("Microsoft.PowerShell.Commands.PSRepositoryItemInfo").

    Your second example picks the first object through the pipeline and create a new object (a PSCustomObject object) that is passed down the pipeline. That new object has a "Microsoft.PowerShell.Commands.PSRepositoryItemInfo" type.

    I'm willing to accept JRV's explanation that the Install-Module expects a specific type of object. I am, however, still of the opinion that the help for the Install-Module is inaccurate (i.e., not specific about the acceptable object type that it accepts from the pipeline).

    My complaint lies with the help text, not the cmdlet.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Wednesday, May 27, 2020 9:27 PM
  • Your first example picks the first object through the pipeline and passes it (intact) down the pipeline. That object retains its type ("Microsoft.PowerShell.Commands.PSRepositoryItemInfo").

    Your second example picks the first object through the pipeline and create a new object (a PSCustomObject object) that is passed down the pipeline. That new object has a "Microsoft.PowerShell.Commands.PSRepositoryItemInfo" type.

    I'm willing to accept JRV's explanation that the Install-Module expects a specific type of object. I am, however, still of the opinion that the help for the Install-Module is inaccurate (i.e., not specific about the acceptable object type that it accepts from the pipeline).

    My complaint lies with the help text, not the cmdlet.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Yes.  The docs should be better.  If you understand how these docs are created then the poor info is understandable.  The developers and documentors need to address this for many commands.  The remoting commands have always been thin of behaviors.  I complained about this with Exchange 2010.  It may never get fixed.

    Currently there is a bug report on missing docs for the type.  Maybe that will cause some changes.


    \_(ツ)_/

    Wednesday, May 27, 2020 9:35 PM
  • Your first example picks the first object through the pipeline and passes it (intact) down the pipeline. That object retains its type ("Microsoft.PowerShell.Commands.PSRepositoryItemInfo").

    Your second example picks the first object through the pipeline and create a new object (a PSCustomObject object) that is passed down the pipeline. That new object has a "Microsoft.PowerShell.Commands.PSRepositoryItemInfo" type.

    That was my theory also, but according to Get-Member, type is PSCustomObject for both:

    PS C:\> Find-Module PSDiscoveryProtocol | select -First 1 -Property * | Get-Member -Force
    
    
       TypeName: Selected.System.Management.Automation.PSCustomObject
    
    Name                       MemberType   Definition
    ----                       ----------   ----------
    pstypenames                CodeProperty System.Collections.ObjectModel.Collection`1[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] pstypenames{get=PSTypeNames;}
    psadapted                  MemberSet    psadapted {ToString, GetType, Equals, GetHashCode}
    psbase                     MemberSet    psbase {ToString, GetType, Equals, GetHashCode}
    psextended                 MemberSet    psextended {Name, Version, Type, Description, Author, CompanyName, Copyright, PublishedDate, InstalledDate, UpdatedDate, LicenseUri, ProjectUri, IconUri, Tags, Includes, PowerShellGetFor…
    psobject                   MemberSet    psobject {BaseObject, Members, Properties, Methods, ImmediateBaseObject, TypeNames, get_BaseObject, get_Members, get_Properties, get_Methods, get_ImmediateBaseObject, get_TypeNames, ToSt…
    Equals                     Method       bool Equals(System.Object obj)
    GetHashCode                Method       int GetHashCode()
    GetType                    Method       type GetType()
    ToString                   Method       string ToString()
    AdditionalMetadata         NoteProperty System.Management.Automation.PSCustomObject AdditionalMetadata=@{summary=Capture and parse CDP and LLDP packets on local or remote computers; isAbsoluteLatestVersion=True; GUID=699f2ddf-…
    Author                     NoteProperty string Author=lahell
    CompanyName                NoteProperty string CompanyName=lahell
    Copyright                  NoteProperty string Copyright=(c) 2019 lahell. All rights reserved.
    Dependencies               NoteProperty Object[] Dependencies=System.Object[]
    Description                NoteProperty string Description=Capture and parse CDP and LLDP packets on local or remote computers
    IconUri                    NoteProperty uri IconUri=https://raw.githubusercontent.com/lahell/PSDiscoveryProtocol/master/images/PSDiscoveryProtocol.png
    Includes                   NoteProperty hashtable Includes=System.Collections.Hashtable
    InstalledDate              NoteProperty object InstalledDate=null
    LicenseUri                 NoteProperty uri LicenseUri=https://raw.githubusercontent.com/lahell/PSDiscoveryProtocol/master/LICENSE
    Name                       NoteProperty string Name=PSDiscoveryProtocol
    PackageManagementProvider  NoteProperty string PackageManagementProvider=NuGet
    PowerShellGetFormatVersion NoteProperty object PowerShellGetFormatVersion=null
    ProjectUri                 NoteProperty uri ProjectUri=https://github.com/lahell/PSDiscoveryProtocol
    PublishedDate              NoteProperty datetime PublishedDate=12.11.2019 21:04:33
    ReleaseNotes               NoteProperty object ReleaseNotes=null
    Repository                 NoteProperty string Repository=PSGallery
    RepositorySourceLocation   NoteProperty string RepositorySourceLocation=https://www.powershellgallery.com/api/v2
    Tags                       NoteProperty Object[] Tags=System.Object[]
    Type                       NoteProperty string Type=Module
    UpdatedDate                NoteProperty object UpdatedDate=null
    Version                    NoteProperty string Version=1.1.0
    
    PS C:\> Find-Module PSDiscoveryProtocol | select -First 1 | Get-Member -Force
    
    
       TypeName: Selected.System.Management.Automation.PSCustomObject
    
    Name                       MemberType   Definition
    ----                       ----------   ----------
    pstypenames                CodeProperty System.Collections.ObjectModel.Collection`1[[System.String, System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]] pstypenames{get=PSTypeNames;}
    psadapted                  MemberSet    psadapted {ToString, GetType, Equals, GetHashCode}
    psbase                     MemberSet    psbase {ToString, GetType, Equals, GetHashCode}
    psextended                 MemberSet    psextended {Name, Version, Type, Description, Author, CompanyName, Copyright, PublishedDate, InstalledDate, UpdatedDate, LicenseUri, ProjectUri, IconUri, Tags, Includes, PowerShellGetFor…
    psobject                   MemberSet    psobject {BaseObject, Members, Properties, Methods, ImmediateBaseObject, TypeNames, get_BaseObject, get_Members, get_Properties, get_Methods, get_ImmediateBaseObject, get_TypeNames, ToSt…
    Equals                     Method       bool Equals(System.Object obj)
    GetHashCode                Method       int GetHashCode()
    GetType                    Method       type GetType()
    ToString                   Method       string ToString()
    AdditionalMetadata         NoteProperty System.Management.Automation.PSCustomObject AdditionalMetadata=@{summary=Capture and parse CDP and LLDP packets on local or remote computers; isAbsoluteLatestVersion=True; GUID=699f2ddf-…
    Author                     NoteProperty string Author=lahell
    CompanyName                NoteProperty string CompanyName=lahell
    Copyright                  NoteProperty string Copyright=(c) 2019 lahell. All rights reserved.
    Dependencies               NoteProperty Object[] Dependencies=System.Object[]
    Description                NoteProperty string Description=Capture and parse CDP and LLDP packets on local or remote computers
    IconUri                    NoteProperty uri IconUri=https://raw.githubusercontent.com/lahell/PSDiscoveryProtocol/master/images/PSDiscoveryProtocol.png
    Includes                   NoteProperty hashtable Includes=System.Collections.Hashtable
    InstalledDate              NoteProperty object InstalledDate=null
    LicenseUri                 NoteProperty uri LicenseUri=https://raw.githubusercontent.com/lahell/PSDiscoveryProtocol/master/LICENSE
    Name                       NoteProperty string Name=PSDiscoveryProtocol
    PackageManagementProvider  NoteProperty string PackageManagementProvider=NuGet
    PowerShellGetFormatVersion NoteProperty object PowerShellGetFormatVersion=null
    ProjectUri                 NoteProperty uri ProjectUri=https://github.com/lahell/PSDiscoveryProtocol
    PublishedDate              NoteProperty datetime PublishedDate=12.11.2019 21:04:33
    ReleaseNotes               NoteProperty object ReleaseNotes=null
    Repository                 NoteProperty string Repository=PSGallery
    RepositorySourceLocation   NoteProperty string RepositorySourceLocation=https://www.powershellgallery.com/api/v2
    Tags                       NoteProperty Object[] Tags=System.Object[]
    Type                       NoteProperty string Type=Module
    UpdatedDate                NoteProperty object UpdatedDate=null
    Version                    NoteProperty string Version=1.1.0

    Wednesday, May 27, 2020 9:35 PM
  • Appears to be fixed in PowerShellGet 3.0 Preview 3. This works:

    PS C:\> Find-PSResource PSDiscoveryProtocol | select -First 1 -Property * | Install-PSResource

    That would be a nice fix.  Maybe it will propagate through all serialized objects.  Azure could sure use this as well as Exchange.   Currently neither behave well in the pipeline.


    \_(ツ)_/

    Wednesday, May 27, 2020 9:37 PM
  • at least there are workarounds for your use case.

    Install-Module -Name (Find-Module "PS*Protocol" | select *| Out-GridView -Title "select module" -PassThru).Name

    I also agree with jrv, that user voice is maybe the better place to get this "fixed", and as your thinking, i would say, install-module is the place to get the selected names property propper unwarpped from the selected PSCustomObject.


    Please remember to mark the replies as answers if they helped.

    Wednesday, May 27, 2020 10:23 PM
  • So you're all fine with the majority of all cmdlets/objects being output from select-object as the type Selected.Whatever.Thetype.GoingIn except for when dealing with modules? I have to conclude that if this were output with the type Selected.Microsoft.PowerShell.Commands.PSRepositoryItemInfo, which would be consistent with the 8 examples below and the dozens more I've tested but did not post, then this issue would not be present. 

    Get-Process | select -First 1 -property * | gm
    
       TypeName: Selected.System.Diagnostics.Process
    
    Get-Service | select * | gm
    
       TypeName: Selected.System.ServiceProcess.ServiceController
    
    Get-ChildItem -File | select -First 1 -property * | gm
    
       TypeName: Selected.System.IO.FileInfo
    
    Get-Item C:\Windows | select * | gm
    
       TypeName: Selected.System.IO.DirectoryInfo
    
    Get-Command -Verb start | select -first 1 -property * | gm
    
       TypeName: Selected.System.Management.Automation.AliasInfo
    
    Get-Acl -Path C:\Windows | select * | gm
    
       TypeName: Selected.System.Security.AccessControl.DirectorySecurity
    
    get-date | select -Property * | gm
    
       TypeName: Selected.System.DateTime
    
    Get-WindowsCapability -Name rsat.act* -Online | select * | gm
    
       TypeName: Selected.Microsoft.Dism.Commands.AdvancedCapabilityObject

    "Your first example picks the first object through the pipeline and passes it (intact) down the pipeline. That object retains its type ("Microsoft.PowerShell.Commands.PSRepositoryItemInfo")."  This is incorrect. I'm not sure what example you're referring to, but even if I just pick the first one, it has lost it's type.

    find-module -name credential* | select -first 1 | gm
    
    
       TypeName: Selected.System.Management.Automation.PSCustomObject

    So the simple, very basic powershell procedure, of grabbing just the first object destroys the type. How is this not being viewed as an issue? It does not do this with anything else that I've found yet. I would not suspect Install-Module as the culprit, as the issue seems to be right here, with the output of select-object, when working with the output of Find-Module as its input.

    Thanks for all your responses. 

    Thursday, May 28, 2020 12:30 AM
  • Appears to be fixed in PowerShellGet 3.0 Preview 3. This works:

    PS C:\> Find-PSResource PSDiscoveryProtocol | select -First 1 -Property * | Install-PSResource

    That would be a nice fix.  Maybe it will propagate through all serialized objects.  Azure could sure use this as well as Exchange.   Currently neither behave well in the pipeline.


    \_(ツ)_/

    Interesting, seems it is an issue with powershellget. 

    "On the other hand "Dmaurer" is arguing that there is something wrong based on a misunderstanding of how PowerShell works."

    Interesting. 

    "My point is that the object type has changed and the object type is required for the remote call.  Select-Object removes the object type."

    I think I've proven otherwise, but still not the issue. 

    "I have addressed this many points above.  It is by design and 7 will behave exactly the same way.  You can pull the source code to dig deeper into how this works."

    Interesting.

    I'm fascinated, you are all over the place. 

    Thank you Leif-Arne Helland for the info/testing. I already had work arounds, but this is a neat one

    Install-Module -Name (Find-Module "PS*Protocol" | select *| Out-GridView -Title "select module" -PassThru).Name

    What's crazy is despite this

    Find-Module -name azure* |select -first 1  | get-member
    
        TypeName: Selected.System.Management.Automation.PSCustomObject

    This still works

    Find-Module -name azure* |select -first 1  | install-module
    In the end, I'm humbled by this discussion as well as happy to have been part of it. Thank you all, even JRV. 


    Thursday, May 28, 2020 2:12 AM
  • You are correct. They are both PSCustomObject. I mistakenly checked the value returned by the Find-Module instead of the output from "Select-Object -First 1". My apologies.

    I'd suggest trying Microsoft's "uservoice" although, it seems to me, to be a bug and not just a documentation issue. If it is a bug it should probably be handled through the https://support.microsoft.com site. However, a Powershell MVP can communicate this directly to the support folks (unless there's no e-mail list or forum for that -- which would be a real shame!). If I were still a MVP I'd do this myself, but I'm not, and I can't.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Thursday, May 28, 2020 9:33 PM
  • The issue is still with "Select-Object" which removes the type if you look at it correctly.

    Example:

    PS C:\scripts> $x = Get-ChildItem test.txt|select *
    PS C:\scripts> $x.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     False    PSCustomObject                           System.Object
    
    
    PS C:\scripts> $f = Get-ChildItem test.txt
    PS C:\scripts> $f.GetType()
    
    IsPublic IsSerial Name                                     BaseType
    -------- -------- ----                                     --------
    True     True     FileInfo                                 System.IO.FileSystemInfo
    
    
    PS C:\scripts>
    
    

    Notice the the type is changed.  When a CmdLet expects a specific type then this will cause it to fail.  For remoted commands that accept "PsObject" we can assume that all objects are of type "PsObject" due to inheritance.   Selecting the object rebuilds it in to a PsCustomObject and throws out the internal type which, I am sure, is the XML structure that is returned by "Find-Module".

    The documentation issue is really  a separate issue.  which needs to be addressed and it seems that PS 7.1 has addressed this behavior in some way.  Perhaps the whole deserialization/serialization system has been updated to avoid this behavior.  We can always hope.  Sometimes those OpenSource guys do good things.  The affect of having engineers from many disciplines on any project.


    \_(ツ)_/

    Thursday, May 28, 2020 10:31 PM
  • I think I would open an issue on Github rather than posting on UserVoice or support.microsoft.com. https://github.com/PowerShell/PowerShellGetv2
    Thursday, May 28, 2020 11:03 PM
  • I think I would open an issue on Github rather than posting on UserVoice or support.microsoft.com. https://github.com/PowerShell/PowerShellGetv2

    I don't believe GitHub will accept issues with Microsoft released products. Documentation issues should be posted to the documentation page as the doc people are a different group.

    Here is the GitHub issues page for the documentation of Install-Module https://github.com/MicrosoftDocs/PowerShell-Docs/issues?utf8=%E2%9C%93&q=%22f3b7d225-4b62-1930-75c5-fc35e1c402ff%22&in=body


    \_(ツ)_/

    Thursday, May 28, 2020 11:45 PM
  • Which is to blame? I really don't know. But If you truly need the properties returned by the Find-Module cmdlet in some other format and you want to have the Install-Module to be able to use the data from the Select-Object to install the module, try this (substituting the module name/s, wildcards, etc. to suit your needs):

         find-Module  MSOnline |select * -expandproperty name |Install-Module

    That produces a System.String object with additional properties of the type 'NoteProperty', and the Install-Module accepts the string value that was the "Name" property of the object created by Find-Module.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Friday, May 29, 2020 10:53 PM
  • Which is to blame? I really don't know. But If you truly need the properties returned by the Find-Module cmdlet in some other format and you want to have the Install-Module to be able to use the data from the Select-Object to install the module, try this (substituting the module name/s, wildcards, etc. to suit your needs):

         find-Module  MSOnline |select * -expandproperty name |Install-Module

    That produces a System.String object with additional properties of the type 'NoteProperty', and the Install-Module accepts the string value that was the "Name" property of the object created by Find-Module.


    --- Rich Matheisen MCSE&I, Exchange Ex-MVP (16 years)

    Simple.  The parameter "Name" accepts a "ValueType" that is a string.  A string is a special case in that it is a ValueType in its use while being an object.  A ValueType has no properties in use unless we explicitly express the property.  The unique thing about a string is that it is an "Object".  When we evaluate it it behaves like any other value.  A string is not a "PsObject".  It is a primitive in the Net Framework.

    I have an excerpt from the designers of PS but it is in a printed medium.  I am going to try to extract it.  It is one of the best statements about what PowerShell is and how it is designed to work.  Some of that statement overcomes earlier ideas of what aa programming language is and how PS is not a classic programming language.  I think it helps to set the stage for how to think through these kinds of issues.

    You may also want to think that this may be one of the chicken and egg problems.


    \_(ツ)_/

    Friday, May 29, 2020 11:39 PM