1

I want to write a cmdlet that changes its behavior depending on its pipeline position. Simplyfied example:

Get-XYZObject | Rename-XYZObject

If the cmdlet is the last in the pipeline it should work directly on a database object.

Get-XYZObject | Rename-XYZObject | Set-XYZValue | Write-XYZObject

If it is not the endpoint it should pipe the object.

Is there a solution without providing a parameter to switch the behaviour?

I searched the web for a solution and read some tutorials about pipeline but found nothing. That could have two reasons:

  1. I do not know what to search for.
  2. It is just not possible.

I tend to the second cause the case

$renamedObject = Get-XYZObject | Rename-XYZObject

could be a problem. Would be nice if someone can clarify that.

4
  • 2
    No, there isn't really a runtime mechanism for indicating that. Usually you'd simply declare an extra switch parameter, like -PassThru, to make the command change its output behavior Commented Mar 23, 2023 at 12:20
  • OK, that a parameter can solve that is obvious. But I really like your suggestion with -PassThru. Thanks! Commented Mar 23, 2023 at 12:26
  • @Darin I do not understand how this could work. Would be nice if you write an answer containing an example which clarifys your suggestion. Commented Mar 23, 2023 at 12:39
  • @TobiasWollgam, removed my answer. Sorry, I was thinking item position in the pipeline input, where you were wanting Cmdlet position in the pipeline chain. Commented Mar 23, 2023 at 18:14

1 Answer 1

1

I think you might be looking for something similar to this, not sure how robust it is or if I would recommend you to use but might be of help.

You can use InvocationInfo.PipelineLength Property, InvocationInfo.PipelinePosition Property and InvocationInfo.Line Property to help you determine if your function is the last statement in a pipeline or even if your function is being piped.

function Test-PipePosition {
    [CmdletBinding()]
    param([Parameter(ValueFromPipeline)] $InputObject)

    begin {
        $lastInPipeline = $false

        # this would mean that the function is not being piped
        if($MyInvocation.Line.StartsWith($MyInvocation.InvocationName)) {
            return
        }

        if($MyInvocation.PipelineLength -eq $MyInvocation.PipelinePosition) {
            $lastInPipeline = $true
        }
    }
    process {
        # if it's not the last, then do stuff
        if(-not $lastInPipeline) {
            $InputObject
        }

    }
    end {
        # if it is the last then do other stuff
        if($lastInPipeline) {
            "I'm last in this pipeline!"
        }
    }
}

Here are some examples:

# Outputs `Get-Process`
Get-Process | Test-PipePosition | ForEach-Object { $_ }

# Outputs `I'm last in this pipeline!`
Get-Process | Test-PipePosition

# Doesn't produce output
Test-PipePosition

# Outputs `I'm last in this pipeline!`
0..10 | Test-PipePosition

Certainly this requires more testing and a much more robust solution might be possible by inspecting the AST.

Sign up to request clarification or add additional context in comments.

1 Comment

Oh, interesting! I will try that tomorrow. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.