Pipeline Errors Install-Module

Welcome Forums General PowerShell Q&A Pipeline Errors Install-Module

This topic contains 6 replies, has 6 voices, and was last updated by

js
 
Participant
3 months, 3 weeks ago.

  • Author
    Posts
  • #104681

    Participant
    Points: 0
    Rank: Member

    Hello,
    My task (or I should say Playing with Powershell Objects) is to create a custom object with the list of installed modules and update them. My oneliner creates the object and pipe it to Install-Module cmdlet, since it has -InputObject parameter which accepts pipeline ByValue,ByPropertyName I'm expecting below command should work – As per my understanding...

    @('SqlServer','ImportExcel') | ForEach-Object {[pscustomobject]@{Name = "$_"}} | Install-Module -Force}

    This is erroring out saying Invalid Argument ...

    After doing some reading, I tried below and it worked.

    @('SqlServer','ImportExcel') | Foreach {Install-Module -Name $_ -Force}

    Why isn't #1 statement working as intended? Can someone help me understand?

  • #104702

    Participant
    Points: 159
    Helping Hand
    Rank: Participant

    If you look further into the help:

    [-FullyQualifiedName] is looking for ModuleSpecification[]

    It's most likely that piping to Import-Module requires the FullyQualifiedName, not a short Name. You also notice that it want a ModuleSpecification. The preferred way would probably be to use Get-Module -ListAvailable to see if the module is available before piping to Import-Module:

    PS C:\WINDOWS\system32> Get-Module -Name TLS, PKI -ListAvailable
    
    
        Directory: C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    
    
    ModuleType Version    Name                                ExportedCommands                                                                                                                        
    ---------- -------    ----                                ----------------                                                                                                                        
    Manifest   1.0.0.0    PKI                                 {Add-CertificateEnrollmentPolicyServer, Export-Certificate, Export-PfxCertificate, Get-CertificateAutoEnrollmentPolicy...}              
    Manifest   2.0.0.0    TLS                                 {New-TlsSessionTicketKey, Enable-TlsSessionTicketKey, Disable-TlsSessionTicketKey, Export-TlsSessionTicketKey...}                       
    
    
    
    PS C:\WINDOWS\system32> Get-Module -Name TLS, DoesNotExist -ListAvailable
    
    
        Directory: C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules
    
    
    ModuleType Version    Name                                ExportedCommands                                                                                                                        
    ---------- -------    ----                                ----------------                                                                                                                        
    Manifest   2.0.0.0    TLS                                 {New-TlsSessionTicketKey, Enable-TlsSessionTicketKey, Disable-TlsSessionTicketKey, Export-TlsSessionTicketKey...}                       
    

    You can then pipe the found modules to Import-Module:

    Get-Module -Name TLS, PKI -ListAvailable | Import-Module -Verbose -Force
    
  • #104707

    Participant
    Points: 0
    Rank: Member

    Hello Rob,

    The cmdlet im piping into is Install-Module. And I don't see required parameters other than Name or Inputobject in the help.

  • #104713

    Participant
    Points: 159
    Helping Hand
    Rank: Participant

    Unless the parameter you're passing to has been explicitly defined as [ValueFromPipelineByPropertyName()] in its code, it will not work like this. Also, if any previous parameter has a parameter that is [ValueFromPipeline()] it will attempt to put the entire object into that as well as doing what you're expecting. This frequently breaks parameter sets and causes errors.

    Instead, you can try something like this:

    @('SqlServer','ImportExcel') | ForEach-Object {
        [pscustomobject]@{
            Name = $_
        }
    } | Install-Module -Name {$_.Name} -Force

    If you check Get-Help Install-Module -Full you'll see that the first positional parameter is:

     -Assembly 
    
            Required?                    true
            Position?                    0
            Accept pipeline input?       true (ByValue)
            Parameter set name           Assembly
            Aliases                      None
            Dynamic?                     false

    Note – position 0
    Note – pipeline input by value

    It's expecting you to provide an object that is some kind of Assembly, so it's likely expecting direct input from an imported DLL or some such. I can't say I've ever see the -Assembly parameter used.

    Funky thing here is that -Name is ALSO position 0 — but there doesn't appear to be a clear way for the PowerShell parser to determine which parameter set you want, so I'd conjecture it probably defaults to -Assembly.

  • #104735

    Participant
    Points: -16
    Rank: Member

    Just throwing this out there... `install-module -Name ' so `install-module -Name 'SqlServer','ImportExcel' -Confirm:$false -Force` should work. Taking your array and passing could be done,, don't have time to write that up. I would recommend adding the -Confirm:$false -Force so you do not have to confirm all the modules to be install.

  • #104765

    Keymaster
    Points: 1,619
    Helping HandTeam Member
    Rank: Community Hero

    So, the docs (https://docs.microsoft.com/en-us/powershell/module/powershellget/install-module?view=powershell-6) indicate that the -Name parameter is indeed supposed to accept module names, in a property named Name, from the pipeline. I would expect this to work:

    @('SqlServer','ImportExcel') | ForEach-Object {[pscustomobject]@{Name = "$_"}} | Install-Module -Force}
    

    But some commands can be a little dinky about custom objects. I'd tend to use Trace-Command and get it to show me what it was doing for parameter binding, to figure out what was happening.

  • #104770
    js

    Participant
    Points: 202
    Helping Hand
    Rank: Participant

    If a parameter that can be passed in the pipe byvalue isn't specified (-InputObject in this case), powershell gets "greedy" and tries to turn other properties in the pipe like Name into what it's looking for (a [PSObject]InputObject). Perhaps a bug (https://github.com/PowerShell/PowerShell/issues/7159)? Usually the byvalue parameter is a string. Learning is hard (Bruce Payette).

    PS C:\Users\js> [pscustomobject]@{Name = 'SqlServer'} | Install-Module -whatif
    
    Install-Module : Invalid value is specified for InputObject parameter.
    At line:1 char:41
    + [pscustomobject]@{Name = 'SqlServer'} | Install-Module -whatif
    +                                         ~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidArgument: (@{Name=SqlServer}:PSObject) [Install-Module], ArgumentException
        + FullyQualifiedErrorId : InvalidInputObjectValue,Install-Module

    EDIT:

    Alternatives:

    PS C:\Users\js> install-module importexcel,sqlserver
    
    PS C:\Users\js> find-module importexcel,sqlserver | install-module

    Maybe you can try to mimic what find-module returns and make your own object. But it's probably not worth it.

    Using "set-psdebug -trace 1", this looks like the reason install-module doesn't like your object:

       if ( >>>> ($inputValue.PSTypeNames -notcontains "Microsoft.PowerShell.Commands.PSRepositoryItemInfo") -and
    DEBUG: 1826+                      >>>> ThrowError -ExceptionName "System.ArgumentException" `

The topic ‘Pipeline Errors Install-Module’ is closed to new replies.