Skip to content

Can we allow script-block parameter values (delay-bind script blocks) for non-pipeline-binding parameters too? #6837

@mklement0

Description

@mklement0

Being able to pass script blocks ad hoc in order to calculate per-input-object parameter values is a great general-purpose feature.

However, it is currently limited to parameters that are explicitly defined as pipeline-binding.

A widely used application of this technique is with Rename-Item's -NewName parameter, where a script block is passed to calculate the new name; e.g.:

# Rename all *.rtf files to *.txt files
Get-Item *.rtf | Rename-Item -NewName {  $_.BaseName + '.txt' } -WhatIf

However, the above only works because -NewName too is defined as pipeline-binding (ValueFromPipelineByPropertyName, in this case).

The ability to pass a script block to any parameter (other than those typed [object] or [scriptblock]) of a command that accepts pipeline input in principle - whether or not that parameter is itself pipeline-binding - would make this technique useful in a much wider array of situations.

Is there a conceptual barrier to removing this restriction (overall, the cmdlet/advanced function would still have to have at least one pipeline-binding parameter)?

Technically, this would be a breaking change, albeit hopefully one that falls into Bucket 3: Unlikely Grey Area:

What happens currently if you try to pass a script block to a differently typed non-pipeline-binding parameters is that an attempt is made to convert the script block to the parameter's type (unless the parameter is [object] or [scriptblock], which would continue to be exempt).
This fails with most types, but in the case of a [string] parameter you currently do get the script block's contents as a string value.
Arguably, though, users who expect script blocks type their parameters a such.


Here's an example with an advanced function:

function Rename-Foo {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [System.IO.FileSystemInfo] $InputObject
        ,
        # WISHFUL THINKING: The `ValueFromPipelineByPropertyName` shouldn't be necessary.
        [Parameter(Mandatory, ValueFromPipelineByPropertyName)]
        [string] $NewName
    )

    process {
        "Will rename $($InputObject.Name) to $NewName."
    }

}

PS> Get-Item foo.txt, bar.txt | Rename-Foo -NewName { $_.Name + '!!' }
Will rename foo.txt to foo.txt!!
Will rename bar.txt to bar.txt!!

Environment data

Written as of:

PowerShell Core v6.0.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Questionideally support can be provided via other mechanisms, but sometimes folks do open an issue to get a

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions