Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proxy function in PowerShell not accepting pipeline input

Tags:

powershell

I've created a proxy function for Remove-Item, which deletes to the recycle bin instead of permanently (using the proxy so that I can seamlessly replace the rm alias, without breaking 3rd party scripts).

However, it doesn't work when a file is piped into the function. The heart of the proxy function is this:

if ($PSBoundParameters['DeletePermanently'] -or $PSBoundParameters['LiteralPath'] -or $PSBoundParameters['Filter'] -or $PSBoundParameters['Include'] -or $PSBoundParameters['Exclude'] -or $PSBoundParameters['Recurse'] -or $PSBoundParameters['Force'] -or $PSBoundParameters['Credential']) {
    if ($PSBoundParameters['DeletePermanently']) { $PSBoundParameters.Remove('DeletePermanently') | Out-Null }
    $scriptCmd = {& $wrappedCmd @PSBoundParameters }
} else {
    $scriptCmd = {& Recycle-Item -Path $PSBoundParameters['Path'] }
}

So, my custom Recycle-Item function is only called if Path is the only parameter. So, something like Get-ChildItem .\temp\ | rm -DeletePermanently works just fine, but Get-ChildItem .\temp\ | rm has an error because the Path passed to Recycle-Item is $null.

I've tried passing $Path instead of $PSBoundParameters['Path'] and tried splatting @PSBoundParameters like the call to $wrappedCmd above, but none of it appears to do much good. I've copied the params from this function to Recycle-Item, to ensure that it is expecting input from the pipeline, but that doesn't seem to help either. Some of those changes appear to pass along the file name, but not the full path, so I don't know if there's some magic inside Remove-Item that I need to replicate to handle a file object from the pipeline.

Recycle-Item is just a basic function:

function Recycle-Item($Path) {
    $item = Get-Item $Path
    $directoryPath = Split-Path $item -Parent

    $shell = new-object -comobject "Shell.Application"
    $shellFolder = $shell.Namespace($directoryPath)
    $shellItem = $shellFolder.ParseName($item.Name)
    $shellItem.InvokeVerb("delete")
}
like image 928
bdukes Avatar asked Apr 10 '26 14:04

bdukes


1 Answers

As mentioned in the comments, the provider cmdlets usually bind on LiteralPath when you pipe objects between them. This way allows Path to support wildcard globbing without the chance of passing ambiguous item paths between cmdlets.

Remove-Item has only two parameter sets, and they are named after their mandatory parameters, Path and LiteralPath

To solve your problem, simply check for all defined parameters that are not one of these two, then pass the appropriate value to Remove-Item based on the $PSCmdlet.ParameterSetName value:

if(@($PSBoundParameters.Keys |Where-Object {@('DeletePermanently','Filter','Include','Exclude','Recurse','Force','Credential') -contains $_}).Count -ge 1){
    # a parameter other than the Path/LiteralPath or the common parameters was specified, default to Remove-Item
    if ($PSBoundParameters['DeletePermanently']) { 
        $PSBoundParameters.Remove('DeletePermanently') | Out-Null 
    }
    $scriptCmd = {& $wrappedCmd @PSBoundParameters }
} else {
    # apart from common parameters, only Path/LiteralPath was specified, go for Recycle-Item
    $scriptCmd = {& Recycle-Item -Path $PSBoundParameters[$PSCmdlet.ParameterSetName] }
}
like image 77
Mathias R. Jessen Avatar answered Apr 12 '26 15:04

Mathias R. Jessen



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!