8000 `-PassThru` as common parameter · Issue #19989 · PowerShell/PowerShell · GitHub
[go: up one dir, main page]

Skip to content

-PassThru as common parameter #19989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
iRon7 opened this issue Jul 17, 2023 · 11 comments
Closed

-PassThru as common parameter #19989

iRon7 opened this issue Jul 17, 2023 · 11 comments
Labels
Issue-Enhancement the issue is more of a feature request than a bug WG-Engine-Pipeline WG-NeedsReview Needs a review by the labeled Working Group

Comments

@iRon7
Copy link
iRon7 commented Jul 17, 2023

Summary of the new feature / enhancement

Why adding the -PassThru switch on a case-by-case bases like: #13713 Add -PassThru parameter to Set-Clipboard?
In my believe every (advanced) function/cmdlet that has a ValueFromPipeline input and no (success stream) pipeline output, should have (an easy standard way to implement)¹ a default -PassThru functionality.

    • any function/cmdlet that doesn't have an explicit custom -PassThru parameter defined, and/or
    • based on an explicit empty output definition [OutputType([System.Void])]
      (but I fear that the OutputType property isn't correctly inplemented in every cmdlet. Anyways a -redundant- common -PassThru won't harm anything)

Take e.g.: Powershell - Get IP Addresses for hostnames from File (more than 150K hostnames)

The Export-Csv appears not to support the -PassThru parameter:

Export-Csv: A parameter cannot be found that matches parameter name 'PassThru'.

But I see no reason why these cmdlets shouldn't have a -PassThru parameter.
Wishful thinking:

... | Export-Csv .\test.csv -PassThru | Format-Table

This purpose might avoid wrapping cmdlet pipelines

This will affect functions and cmdlets along with:

Get-command | Where-Object { $_.Parameters } | Where-Object {
    $_.Parameters.getEnumerator().Foreach{ $_ }.Value.Attributes.ValueFromPipeline -eq $True -and
    !$_.OutputType -and !($_.Parameters.get_Keys() -eq 'PassThru')
}

A automated -PassThru parameter might even be included in some very common cmdlets which basically makes a cmdlet as Tee-Object redundant:

Tee-Object -PassThru comment
Tee-Object -FilePath .\Test.log Out-File -PassThru -FilePath .\Test.log
Tee-Object -Variable MyVar Set-Variable -PassThru -Name MyVar already exists
(Tee-Object -Host) Out-Host -PassThru See: #19827
@iRon7 iRon7 added Issue-Enhancement the issue is more of a feature request than a bug Needs-Triage The issue is new and needs to be triaged by a work group. labels Jul 17, 2023
@iRon7 iRon7 changed the title Standard -PassThru functionality for every (advanced) function / cmdlet. -PassThru as comon parameter Jul 17, 2023
@jhoneill
Copy link

In my believe every (advanced) function/cmdlet that has a ValueFromPipeline input and no (success stream) pipeline output, should have (an easy standard way to implement)¹ a default -PassThru functionality.

I think that is a pretty good design goal - but it is really the job of the command author to make it happen, which is why we have a piecemeal "add it here" , "add it there" . A task to find all the places it should be present and adding it where it is missing would seem like a smart thing...
Adding -PassThru logic as part of common parameters may cause more problems than it solves (for example I was working with a pipeline of 200,000 objects today. Nothing is output in the process block but things are output in the end block. Anything which checks for output would need to buffer everything and then output it at after the end / clean).

@iRon7
Copy link
Author
iRon7 commented Jul 18, 2023

@jhoneill,

A task to find all the places it should be present and adding it where it is missing would seem like a smart thing...

That will certainly add some value, but I think it shouldn't just concern native PowerShell cmdlets but also custom Advanced Functions created in the field.

Adding -PassThru logic as part of common parameters may cause more problems than it solves

Even without any (output-check) logic, using the -PassThru switch will just be something you shouldn't use on a script that already outputs to the success stream (like ConvertTo-Csv -PassThru, as it will mix up the passed through input with the actual output) but it won't break anything existing.

But I agree; it might lead to confusion if some one tries to actually do this on a function/cmdlet that already output to the success stream. So, what about scripts that have explicitly set the OutputType to System.Void? Like:

function Test {
    [CmdletBinding()]
    [OutputType([System.Void])]
    param(
        [Parameter(ValueFromPipeline=$true)]
        $InputObject
    )
}

Meaning, all of these conditions should be true:

  • The function shouldn't have a -PassThru parameter defined by itself
  • The function should have a ValueFromPipeline parameter
  • The function should have an OutputType defined that is set to Void ($_.OutputType.Name -eq 'Void')

@iRon7 iRon7 changed the title -PassThru as comon parameter -PassThru as common parameter Jul 18, 2023
@jhoneill
Copy link

I think (and it is only one view). OutputType is widely left unset, and only very rarely set to Void. Yes we could save authors a little effort and enable passthru for those functions which do.

I think the objection to doing it comes from command authors... take a version of the SO article.
I have a Remove-Thing command, so I can do Get-Thing | where-object ... | Remove-Thing as author it never crossed my mind that someone would want to see what was removed and have ... | Remove-Thing -passthru | Ft. Enabling this would help users of my command IF they only do things which make sense with things that have been removed.
And then we get the argument "I don't want users to be able to do something stupid" vs "Don't stop me doing something because someone else might be stupid" .
The user of my command can do Get-Thing | where-object -outvariable Things ... | Remove-Thing and do $things | ft as its own command so I can't stop them doing something stupid, I just make them do it asynchronously. And if where is not selecting the right things they don't see that until remove has tried to delete them.
So the user needs to do Get-Thing | where-object -outvariable Things ... | ft ; $things | remove-thing It would be better for them if they could just do Get-Thing | where-object -outvariable Things ... | Out-host -passthru | Remove-Thing, but of course out-host doesn't support passthru.

The other issue is if we look at -Passthru in (for example) add-Member it doesn't matter if we do
$things | Add-Member -passthru
or
Add-Member -in $things | -passthru

I think the common parameter route only works for the first one.

There's still a good idea here, even if we only get to adding something to best practices guide to say "support -Passthru" - but maybe others have ideas for how the original idea can be made to work nicely.

@iRon7
Copy link
Author
iRon7 commented Jul 20, 2023

@jhoneill,

... | Remove-Thing -passthru | Ft. Enabling this would help users of my command IF they only do things which make sense with things that have been removed.

I have done an additional Feature Request / Idea for this: #20001 Add Write-* proxy for each Format-* cmdlet

And then we get the argument "I don't want users to be able to do something stupid" vs "Don't stop me doing something because someone else might be stupid"

I think, the -PassThru parameter should push for a standard (consistent) expectation even it is not always the desired implementation (e.g. in the case of a Remove-Thing function which its own -Filter parameter, it should implement its own -PassRemoved or even -PassLeftover parameters possibly aside from a standard -PassThru)
I guess the standard should be something like this:

function Test {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline=$true)] $InputObject,

        [switch] $PassThru
    )

    process {
         if ($PassThru) { $_ }
         # further process tasks that come *after* the passthru
    }
}

Where any (unintended) deviations from the standard PassThru implementation should be prevented.
(but not written in stone, if the author wants to do his own PassThru implementation, he can do so by adding a normal "custom" $PassThru parameter)
Meaning, avoid:

even if we only get to adding something to best practices guide to say "support -Passthru"

Agree.
Btw, I renounced from the [OutputType([System.Void])] trigger idea as it contradicts itself (when set, it actually allows for a -passthru- output 👎), but still think that a "trigger switch" for a common/automated standard -PassThru implementation could be welcome. (maybe a [CmdletBinding(SupportsPassThru)]).

Whatever decision is made for this request, I will push for documentation afterwards as e.g. a section in about Functions Advanced Parameters document.

@dkaszews
Copy link
Contributor

How about ... | Tee-Object -Process { Export-Csv .\test.csv } | Format-Table?

It would have similar semantics to ForEach-Object { $_ | $action; $_ }, but act on the entire pipe once it ends, instead of individual objects. In fact, it could probably be implemented with something like ForEach-Object -Begin { $pipe = [List[object]]:new() } -Process { $pipe.Add($_); $_ } -End { $pipe | $action }, save for scoping and maybe outputting where it should not.

This kind of solution would be way more generic and more closely match how Linux uses tee and process substitution.

@iRon7
Copy link
Author
iRon7 commented Jul 22, 2023

@dkaszews,

How about...

I like the generic Tee-Object -Process idea and would suggest to write a seperate purpose for that as this doesn't exclude the initial -PassThru purpose which -I think- is easier to understand for a average PowerShell user.

@dkaszews 8000
Copy link
Contributor

@iRon7

write a seperate purpose

You mean separate proposal/issue/feature request?

@kilasuit kilasuit added the WG-NeedsReview Needs a review by the labeled Working Group label Jul 22, 2023
@mklement0
Copy link
Contributor
mklement0 commented Aug 16, 2023

@iRon7, re:

the -PassThru parameter should push for a standard (consistent) expectation

Note that the cmdlets that currently implement their own -PassThru switch mostly use semantics that differ from your proposal:

  • They pass the resulting object(s) through, not the input object(s), if any.
  • They do so whether or not there is pipeline input.

A few examples: Import-Module, Set-Variable, Expand-Archive , Rename-Item, Start-Process: with -PassThru, they emit the resulting module, variable object, file-system-info objects, process object.

The only exception I'm aware of is Set-Content, which truly passes its input through. (While Compare-Object passes input through too, it only does so selectively, and with ETS decorations.)

@dkaszews
Copy link
Contributor

I have written up a proposal, but in the process (pun maybe intended) came up with so many opens, that sprinkling -PassThru where applicable may be the better way to go.

@mklement0
Copy link
Contributor

Thanks for writing up a new proposal, @dkaszews - indeed, there are challenging conceptual issues to work out, but I don't think that -PassThru as a common parameter that the the infrastructure handles automatically can ever work, as implied by my previous comment: the predominant semantics are to pass through (out) whatever the cmdlet does with the input, not the input.

@iRon7
Copy link
Author
iRon7 commented Aug 17, 2023

@mklement0,

Note that the cmdlets that currently implement their own -PassThru switch mostly use semantics that differ from your proposal

Good point, to be honest, I was aware but didn't completely thinking this through assuming that there would be a few exceptions to what you would expect¹ and not that there would be just one "consistent" Set-Content.

but I don't think that -PassThru as a common parameter that the the infrastructure handles automatically can ever work

You're right, a common -PassThru with a consistent semantics would break the current individual implementations.
Therefore I will close this issue and open a new issue:

#20133 A common -Reprocess parameter for passing through the current input item.

  1. As the parameter -Passthru only includes a verb, I would expect that it passes the current item ($_) as that is common for all concerned cmdlets

@iRon7 iRon7 closed this as completed Aug 17, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs-Triage The issue is new and needs to be triaged by a work group. label Aug 17, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Enhancement the issue is more of a feature request than a bug WG-Engine-Pipeline WG-NeedsReview Needs a review by the labeled Working Group
Projects
None yet
Development

No branches or pull requests

5 participants
0