Search code examples
powershellparameterspipeline

Pass multiple values through pipeline


I want to be able to pass multiple values through the pipeline for a module I am building. The module is built around a specific SQL Database Schema so i designed this function to return all databases of that schema:

function Get-TRISDatabases {
    param (
        [parameter(mandatory=$false)]
        [string]$ServerAddress = "localhost",
        [parameter(mandatory=$false)]
        [switch]$Name
    )
    Begin {
        $Query_GetDatabases = "
            SELECT Name, create_date, user_access_desc, state_desc, recovery_model_desc FROM   sys.databases WHERE  CASE
                WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME(name) + '.[dbo].[CRISFiles]', 'U')
            END IS NOT NULL
        "
    }

    Process {
        ## Get Data
        $rValue = Invoke-Sqlcmd2 -Query $Query_GetDatabases -ServerInstance $ServerAddress

        ## Return values
        if ($Name) {
            Return $rValue.Name
        }
        else {
            Return $rValue
        }
    }

    End {
        ## Purge Variables
        Remove-Variable Query_GetDatabases, rValue
    }
}

This works fine but what I want is to be able to pass both the $serverAddress and the $rValue variables through the pipeline. This is so i can run other commands like so:

Get-TRISDatabases -name -ServerAddress "server1" | Remove-TRISDeadLinks

Instead of what i have at the moment which would be:

Get-TRISDatabases -name -ServerAddress "server1" | Remove-TRISDeadLinks -ServerAddress "server1"

I tried putting the server address in the rValue object as well but i would have to change every other script to user the server address rValue.ServerAddress for that to work.

Remove-TRISDeadLinks Param block:

param (
    [parameter(
        Mandatory=$false, Position=1,ValueFromPipeline=$false
    )]
    $ServerAddress = "localhost",

    [parameter(
        Mandatory=$false, Position=2,ValueFromPipeline=$true
    )]
    $Databases
)

-

.EXAMPLE
Remove-TRISBrokenLinks -ServerAddress "localhost" -Databases "Database1"

    Manually entering the server address and database

.EXAMPLE 
Remove-TRISBrokenLinks -ServerAddress "localhost" -Databases "Database1", "Database2"

    Runs against an array of databases names

.EXAMPLE 
Get-TRISDatabases -ServerAddress "Localhost" -name | Remove-TRISBrokenLinks

    Uses the Get-TRISDatabases function to pass all TRIS databases to the function

Solution

  • Generally, a process script block allows outputting multiple objects just like any other script block; e.g.:

    PS> 'one', 'two' | & { param([Parameter(ValueFromPipeline)] $str) process { $str; 'hi' } } 
    one
    hi
    two
    hi
    

    Remember that return <object> is just syntactic sugar for outputting <object> and returning from the script block, and that you don't need return to output an object.


    Given your specific requirements, however - binding two parameters of another function with your function's output via the pipeline - you need to:

    • make Get-TRISDatabases output a custom object whose properties are the arguments to pass to both parameters.

    • define your other function to bind those properties from the pipeline by property name.

    # Get-TRISDatabases ...
    
    Process {
        ## Get Data
        $rValue = Invoke-Sqlcmd2 -Query $Query_GetDatabases -ServerInstance $ServerAddress
    
        # Output a custom object with both $rValue and the server address
        [pscustomobject] @{
          ServerAddress = $ServerAddress
          Databases = if ($Name) { $rValue.Name } else { $rValue }
        }
    
    }
    
    # ...
    

    Then define your Remove-TRISDeadLinks param() block as follows (PSv3+; note that parameters are non-mandatory by default, and that their position is implied by their declaration order):

    # Remove-TRISDeadLinks ...
    [CmdletBinding()]
    param (
        [Parameter(ValueFromPipelineByPropertyName)]
        $ServerAddress = "localhost"
        ,   
        [Parameter(ValueFromPipelineByPropertyName)]
        $Databases
    )