Home > Software design >  Is it possible to set parameter positions for default commandlets?
Is it possible to set parameter positions for default commandlets?

Time:02-05

For example I would like the Select-Object commandlet to interpret Get-ChildItem|Select-Object 1 as Get-ChildItem|Select-Object -First 1

I have been getting by with "Wrappers" like this for my most common commandlets:

function Select-Object{
    [CMDletbinding()]
    param (
        [Parameter(ValueFromPipeline)]
        $InputObect, 
        [Parameter(Position = 1)]
        [int]$First,
        [Parameter(Position = 2)]
        [int]$Last
    )
    $input | Select-Object -First $First -Last $Last
}

But there are sometimes buggy and I always rewrite it to add more parameters.

I have been reading the docs and have not found anything other than parametersplicing.

It does not have to be an official solution. So if anyone has come up with a solution to this I would like to know.

PS: I know this is can lead to confusing code, but I am intending to only use it for an interactive\terminal sessions. Doing gci | sel 1 is infinitely more preferable to Get-ChildItem | Select-Object -First 1

Any help would be greatly appreciated!

CodePudding user response:

For wrappers like this you should use a ProxyCommand. Most of the code below can be auto-generated for you via its .Create(..) Method:

[System.Management.Automation.ProxyCommand]::Create((Get-Command Select-Object))

Using only the 2 parameters you're interested in -First and -Last in addition to the pipeline parameter, the function would look like this:

function sel {
    [CmdletBinding()]
    param(
        [Parameter(ValueFromPipeline)]
        [object] $InputObject,

        [Parameter(Position = 1)]
        [int] $First,

        [Parameter(Position = 2)]
        [int] $Last
    )

    begin {
        $wrapper  = { Microsoft.PowerShell.Utility\Select-Object @PSBoundParameters }
        $pipeline = $wrapper.GetSteppablePipeline($MyInvocation.CommandOrigin)
        $pipeline.Begin($PSCmdlet)
    }
    process {
        $pipeline.Process($InputObject)
    }
    end {
        $pipeline.End()
    }
}

Now you can use positional binding without problems:

0..10 | sel 1   # for `-First 1`
0..10 | sel 1 1 # for `-First 1` `-Last 1`

As for parameter splicing you might referring to what's known as Splatting in . For that you can look into about Splatting. As an example the code above is using splatting with the automatic variable $PSBoundParameters.

  • Related