SokIsKedu
SokIsKedu

Reputation: 316

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

Upvotes: 0

Views: 1350

Answers (2)

Mathias R. Jessen
Mathias R. Jessen

Reputation: 175065

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

Upvotes: 3

Mike Garuccio
Mike Garuccio

Reputation: 2728

@Mathias is correct but from the looks of your question you are using the Write-Host outputs as your actual return values for the user rather than actually returning data. In which case you really want to do something more like this. but as was already said, DO NOT use Write-Host for anything outside of early development/debugging of a script.

Function test1
{
  param(
  [Parameter(Mandatory=$false,ValueFromPipeline=$True)]
  $PrevRes = @())
  $PrevRes += 'alpha'
  return ($PrevRes)
}

Upvotes: 1

Related Questions