Retain type when using Select-Object

This may be a silly question, but I’d really like to hear your opinions. I pick a module to install and pipe it to Install-Module which works fine.

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

If I use Select-Object to get all the properties, it no longer works.

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

I assume it’s failing because it is now

TypeName: Selected.System.Management.Automation.PSCustomObject

instead of

TypeName: Microsoft.PowerShell.Commands.PSRepositoryItemInfo

The help for Install-Module is quite unhelpful as well.

    -InputObject <PSObject[]>
        {{Fill InputObject Description}}
        
        Required?                    true
        Position?                    0
        Default value                None
        Accept pipeline input?       True (ByPropertyName, ByValue)
        Accept wildcard characters?  false

INPUTS
    PSGetItemInfo

The reason this even came up is trying to give the user more info to choose which module(s) to install

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

Now of course I could work around in several ways such as

$correctedmodules = $modules | foreach-object {find-module -name $_.name}

Or just

$modules | foreach-object {install-module -name $_.name}

But I just wonder if there is a way to select more/all members while retaining the original type. Or if there is another reason the inputobject is not accepting the object. It says byvalue and byproperty - surely it still has the property/properties required and the value type shows simply PSObject which either should fulfill? I do plan on looking at the source code when I have some more time. Thanks in advance.

Here you should understand that the -InputObject parameter accepts the value in the form of a module as an object either by property name or by value itself, and that doesn’t mean that it can accept any psobject other than module object. Every CmdLet which accepts input in the form of psobject validates the object type first then proceed it further.

However, Select-Object is not to select the object, it is to select the properties of an object and returns in the form of PSCustomObject

Try this out to create an empty pscustomobject with the custom properties in the Select-Object statement

[pre]
C:&gt; ($Obj = “” | Select-Object -Property FirstName, LastName, Department, Role, IsEnabled)

FirstName :
LastName :
Department :
Role :
IsEnabled :

C:&gt; $Obj.GetType()

IsPublic IsSerial Name BaseType


True False PSCustomObject System.Object
[/pre]

I’ve seen the same as what OP is describing and I understand the issue and it’s, as you said, related to parameter binding and binding by type. But doesn’t it seem odd that if you do ‘select *’ wouldn’t you assume it would return the same object type as you get without that? I suppose I can understand why this happens but curious if anything can be done with select-object or the PS parser that could help with this… For the time being you just have to understand and plan for these instances…

Yes it does seem to be inconsistent, given the following example, it suggests that it DOES in fact select the object (or should)

$user = Get-ADuser -Filter "Name -like 'administrator*'" -Properties * | select *
$user | gm

which returns what I expect, an ADUser object with all properties

   TypeName: Selected.Microsoft.ActiveDirectory.Management.ADUser

Kiran, what you are suggesting is that this is no longer a module, just because it has additional properties? Why isn’t that the case for ADUser?

$module = Find-Module pscredentialtools | select *
$module


Name                       : PSCredentialTools
Version                    : 1.1.0
Type                       : Module
Description                : PSCredentialTools provides various methods for securely storing and retrieving credentials used in PowerShell scripts
Author                     : Mike Lacher
CompanyName                : MikeLacher
Copyright                  : (c) 2018 Microsoft Corporation. All rights reserved
PublishedDate              : 5/9/2019 3:49:33 PM
InstalledDate              : 
UpdatedDate                : 
LicenseUri                 : https://github.com/Microsoft/PSCredentiaTools/blob/master/LICENSE
ProjectUri                 : https://github.com/Microsoft/PSCredentialTools
IconUri                    : 
Tags                       : {Credential, PowerShell, PSModule}
Includes                   : {Function, RoleCapability, Command, DscResource...}
PowerShellGetFormatVersion : 
ReleaseNotes               : https://github.com/Microsoft/PSCredentialTools/blob/master/changelog.md
Dependencies               : {}
RepositorySourceLocation   : https://www.powershellgallery.com/api/v2
Repository                 : PSGallery
PackageManagementProvider  : NuGet
AdditionalMetadata         : @{summary=PSCredentialTools provides various methods for securely storing and retrieving credentials used in PowerShell scripts; 
                             releaseNotes=https://github.com/Microsoft/PSCredentialTools/blob/master/changelog.md; versionDownloadCount=275; ItemType=Module; 
                             copyright=(c) 2018 Microsoft Corporation. All rights reserved; PackageManagementProvider=NuGet; CompanyName=Microsoft Corporation; 
                             SourceName=PSGallery; description=PSCredentialTools provides various methods for securely storing and retrieving credentials used 
                             in PowerShell scripts; created=5/9/2019 3:49:33 PM -05:00; published=5/9/2019 3:49:33 PM -05:00; developmentDependency=False; 
                             NormalizedVersion=1.1.0; downloadCount=968; GUID=89b06e4f-42a4-4d7b-bb59-495e35d0b270; lastUpdated=5/25/2020 8:07:28 PM -05:00; 
                             Authors=Mike Lacher; updated=2020-05-25T20:07:28Z; Functions=Export-PSCredential Import-PSCredential New-PSCredential 
                             ConvertFrom-FIPSSecureString ConvertTo-FIPSSecureString ConvertTo-PKISecureString ConvertFrom-PKISecureString; 
                             isLatestVersion=True; PowerShellVersion=4.0; IsPrerelease=false; isAbsoluteLatestVersion=True; packageSize=25765; tags=Credential 
                             PowerShell PSModule; FileList=PSCredentialTools.nuspec|changelog.md|contributing.md|LICENSE|PSCredentialTools.psd1|readme.md|docs\C
                             onvertFrom-FIPSSecureString.md|docs\ConvertFrom-PKISecureString.md|docs\ConvertTo-FIPSSecureString.md|docs\ConvertTo-PKISecureStrin
                             g.md|docs\Export-PSCredential.md|docs\Import-PSCredential.md|docs\New-PSCredential.md|Functions\Convert-SecureStringTo32ByteKey.ps1
                             |Functions\ConvertFrom-FipsSecureString.ps1|Functions\ConvertFrom-PKISecureString.ps1|Functions\ConvertTo-FIPSSecureString.ps1|Func
                             tions\ConvertTo-PKISecureString.ps1|Functions\Export-PSCredential.ps1|Functions\Import-PSCredential.ps1|Functions\New-Password.ps1|
                             Functions\New-PSCredential.ps1|Functions\Set-AzureCmdlets.ps1; requireLicenseAcceptance=False}

It looks like a module to me. Why doesn’t it retain the type in this case when it does in so many others? That’s the question here.

Out of all the tests I’ve done so far, the module is the only object that doesn’t return as it’s own type, selected.

 

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

So this leads me to believe there is a bug here and possibly elsewhere as Peter eluded to. The question is, is it an issue with Select-Object or with the Powershellget provider? If I had to guess I’d say select object. What do you guys/gals think?

Not really sure, looks like the Get-Member is judging the type based on the parameters available, but if you actually go by GetType() method, it shows the type as PSCustomObject with the Select-Object statement…

[pre]

PS C:\Users\Kiran> $ServiceObject = Get-Service BITS
PS C:\Users\Kiran> $ServiceObject.GetType()

IsPublic IsSerial Name BaseType


True False ServiceController System.ComponentModel.Component

PS C:\Users\Kiran> $ServiceSelect = Get-Service BITS | Select *
PS C:\Users\Kiran> $ServiceSelect.GetType()

IsPublic IsSerial Name BaseType


True False PSCustomObject System.Object

[/pre]

With the best of my knowledge, what I know is Select-Object will create a new PSCustomObject and return the object.

Please refer to the description section in the Microsoft Docs below…

https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/select-object

Thank you.

Thanks Kiran. So if I understand you correctly, you believe the select-object is working properly for modules but is not functioning properly for the other examples I’ve shown? Regardless of the type, the pipeline is halted in this particular scenario, while working fine in the many examples I’ve given, plus the countless more I didn’t post. As I told JRV, if you’re not sure why this is working differently then the rest, perhaps it’s better to let someone else answer? It seems you both are saying select-object shouldn’t be used in the pipeline… which is anti powershell from everything I’ve ever read. It just seems if this one or few cases fail when the rest do not, there is an issue?

this could also be ps versioning issues for you.

i just tested

get-module activedirectory |gm

get-module activedirectory|select *|gm

get-module activedirectory|select verions|gm

all 3 seem to be returning: TypeName: System.Management.Automation.PSModuleInfo

It appears it may be an issue with powershellget. It also may be resolved in version 3.

https://social.technet.microsoft.com/Forums/en-US/9491bdec-5971-4ab3-82ca-ee8811855230/selectobject-returning-selected-pscustomobject-instead-of-selected-type?forum=winserverpowershell