powershellreturnoutputsuppress

Powershell: Supress the output to console if it is pipelined


I am writing a search tool on Powershell and I ran into a problem that I cannot suppress the return of a function and it is always printed to console. To make it clear I made some smaller test functions.

Function test1
{
    param(
    [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
    $PrevRes = 0)
    write-host "alfa"
    return ($PrevRes+1)
}

Function test2
{
 param(
    [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
    $PrevRes = 0)
    write-host "beta"
    return ($PrevRes+1) 
}

Function test3
{
 param(
    [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
    $PrevRes = 0)
    write-host "omega"
    return ($PrevRes+1)
}

test1 gives:  
alfa
1

when test1 | test2:
alfa
beta
2

when test | test2 | test3:
alfa
beta
omega
3

when test | test3 | test2:
alfa
omega
beta
3

The problem is I do not know in what order these functions will be called and what I need is to make sure if there is no pipeline at the end, the return would not be printed to the screen, but I still need to access the value itself.

I want an output like this:

test1 gives:  
alfa


when test1 | test2:
alfa
beta


when test | test2 | test3:
alfa
beta
omega


when test | test3 | test2:
alfa
omega
beta

This is a tool for a customer so solution like:

$tst = test1 |test2

is not good because you know, a customer is a customer, he wouldn't know how to use it.

Is there a way to do it with powershell which I missed online?

Any solution would be useful if it does not involve any action from the customer

Thank you in advance


Solution

  • To answer the question

    is there a way to determine in the function itself if the return value is pipelined or not?

    Yes there is. Inspect the $MyInvocation automatic variable and compare the PipelineLength and PipelinePosition properties:

    if($MyInvocation.PipelinePosition -lt $MyInvocation.PipelineLength){
        return $PrevRes + 1
    }
    

    Original answer follows below.


    Very simple solution:

    Don't use Write-Host in your scripts.

    As the name indicates, it will write stuff directly to the host application

    If you need to keep these statements for debugging purposes, use the Write-Debug or Write-Verbose cmdlets instead:

    function test1
    {
        param(
        [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
        $PrevRes = 0)
        Write-Verbose "alfa"
        return ($PrevRes+1)
    }
    
    function test2
    {
     param(
        [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
        $PrevRes = 0)
        Write-Verbose "beta"
        return ($PrevRes+1) 
    }
    
    function test3
    {
     param(
        [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
        $PrevRes = 0)
        Write-Verbose "omega"
        return ($PrevRes+1)
    }
    

    If you need to increment the $PrevRes value between cmdlets you could use a variable from the calling scope (although this is somewhat of an anti-pattern, and I would strongly recommend against it):

    function test1 {
      Write-Host 'alpha'
      $global:PrevRes++
    }
    
    function test2 {
      Write-Host 'beta'
      $global:PrevRes++
    }
    
    function test3 {
      Write-Host 'omega'
      $global:PrevRes++
    }
    

    Then use like:

    PS> test1; test2; test3
    alpha
    beta
    omega
    PS> $PrevRes
    3