powershellrm

Is there any way I can use rm -rf in PowerShell?


I know that I can use rm -r -fo to remove a folder and all its content in PowerShell. But is there any way I can use rm -rf in PowerShell?

I tried to add the below scripts into my $Profile, but both did not work.

  1. First try:

    function rm -rf() {
        rm -r -fo
    }
    
  2. Second try:

    Set-Alias rm -rf "rm -r -fo"
    

Solution

  • As suggested in the comments, you can write a proxy function, that adds the -rf parameter to Remove-Item. If you then set the alias rm to point to your proxy function instead of Remove-Item, you will be able to use rm -rf like in Unix, while still having the opportunity to use all other parameters of Remove-Item. You will basically have Remove-Item with the additional parameter -rf.

    As documented in iRon's excellent Q&A, you can generate the proxy function body with the following commands:

    $MetaData = [System.Management.Automation.CommandMetaData](Get-Command Remove-Item)
    [System.Management.Automation.ProxyCommand]::Create($MetaData)
    

    Which will give you:

    [CmdletBinding(DefaultParameterSetName='Path', SupportsShouldProcess=$true, ConfirmImpact='Medium', SupportsTransactions=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkID=113373')]
    param(
        [Parameter(ParameterSetName='Path', Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [string[]]
        ${Path},
    
        [Parameter(ParameterSetName='LiteralPath', Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
        [Alias('PSPath')]
        [string[]]
        ${LiteralPath},
    
        [string]
        ${Filter},
    
        [string[]]
        ${Include},
    
        [string[]]
        ${Exclude},
    
        [switch]
        ${Recurse},
    
        [switch]
        ${Force},
    
        [Parameter(ValueFromPipelineByPropertyName=$true)]
        [pscredential]
        [System.Management.Automation.CredentialAttribute()]
        ${Credential})
    
    
    dynamicparam
    {
        try {
            $targetCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Remove-Item', [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters)
            $dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object { $_.Value.IsDynamic })
            if ($dynamicParams.Length -gt 0)
            {
                $paramDictionary = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
                foreach ($param in $dynamicParams)
                {
                    $param = $param.Value
    
                    if(-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name))
                    {
                        $dynParam = [Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes)
                        $paramDictionary.Add($param.Name, $dynParam)
                    }
                }
                return $paramDictionary
            }
        } catch {
            throw
        }
    }
    
    begin
    {
        try {
            $outBuffer = $null
            if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
            {
                $PSBoundParameters['OutBuffer'] = 1
            }
            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Remove-Item', [System.Management.Automation.CommandTypes]::Cmdlet)
            $scriptCmd = {& $wrappedCmd @PSBoundParameters }
            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
            $steppablePipeline.Begin($PSCmdlet)
        } catch {
            throw
        }
    }
    
    process
    {
        try {
            $steppablePipeline.Process($_)
        } catch {
            throw
        }
    }
    
    end
    {
        try {
            $steppablePipeline.End()
        } catch {
            throw
        }
    }
    <#
    
    .ForwardHelpTargetName Microsoft.PowerShell.Management\Remove-Item
    .ForwardHelpCategory Cmdlet
    
    #>
    

    You can paste this – as is – directly into your own function definition and you will already have a function that does the same as Remove-Item.

    To add the parameter -rf, add the the following parameter definition:

    [Alias('RF')]
    [switch]
    $RecurseForce
    

    To not pass it to Remove-Item directly, add the following line to the dynamicparam block:

    $PSBoundParameters.Remove('RecurseForce') | Out-Null
    

    Then you just need to handle the call of Remove-Item, when the -rf parameter is provided. To do so, change the line $scriptCmd = {& $wrappedCmd @PSBoundParameters } to:

    if ($RecurseForce) {
        $scriptCmd = {& $wrappedCmd @PSBoundParameters -Recurse -Force }
    } else {
        $scriptCmd = {& $wrappedCmd @PSBoundParameters }
    }
    

    Furthermore, it is recommended to remove the OutBuffer-related code and to replace all throw statements by $PSCmdlet.ThrowTerminatingError($_).

    In the following full example, I named the proxy function Remove-ItemProxy and made all the changes I already described. In the end I call Set-Alias to make it available through rm. No worries, Set-Alias will only affect your current session and won't alter your system permanently. You can copy and paste the following block into your PowerShell profile and whenever you open a PowerShell session, you will be able to use rm -rf:

    function Remove-ItemProxy {
        [CmdletBinding(DefaultParameterSetName='Path', SupportsShouldProcess=$true, ConfirmImpact='Medium', SupportsTransactions=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkID=113373')]
        param(
            [Parameter(ParameterSetName='Path', Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
            [string[]]
            ${Path},
    
            [Parameter(ParameterSetName='LiteralPath', Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
            [Alias('PSPath')]
            [string[]]
            ${LiteralPath},
    
            [string]
            ${Filter},
    
            [string[]]
            ${Include},
    
            [string[]]
            ${Exclude},
    
            [switch]
            ${Recurse},
    
            [switch]
            ${Force},
    
            [Parameter(ValueFromPipelineByPropertyName=$true)]
            [pscredential]
            [System.Management.Automation.CredentialAttribute()]
            ${Credential},
            
            [Alias('RF')]
            [switch]
            $RecurseForce)
    
    
        dynamicparam
        {
            try {
                $PSBoundParameters.Remove('RecurseForce') | Out-Null
                $targetCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Remove-Item', [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters)
                $dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object { $_.Value.IsDynamic })
                if ($dynamicParams.Length -gt 0)
                {
                    $paramDictionary = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
                    foreach ($param in $dynamicParams)
                    {
                        $param = $param.Value
    
                        if(-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name))
                        {
                            $dynParam = [Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes)
                            $paramDictionary.Add($param.Name, $dynParam)
                        }
                    }
                    return $paramDictionary
                }
            } catch {
                $PSCmdlet.ThrowTerminatingError($_)
            }
        }
    
        begin
        {
            try {
                $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Remove-Item', [System.Management.Automation.CommandTypes]::Cmdlet)
                if ($RecurseForce) {
                    $scriptCmd = {& $wrappedCmd @PSBoundParameters -Recurse -Force }
                } else {
                    $scriptCmd = {& $wrappedCmd @PSBoundParameters }
                }
                $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
                $steppablePipeline.Begin($PSCmdlet)
            } catch {
                $PSCmdlet.ThrowTerminatingError($_)
            }
        }
    
        process
        {
            try {
                $steppablePipeline.Process($_)
            } catch {
                $PSCmdlet.ThrowTerminatingError($_)
            }
        }
    
        end
        {
            try {
                $steppablePipeline.End()
            } catch {
                $PSCmdlet.ThrowTerminatingError($_)
            }
        }
        <#
    
        .ForwardHelpTargetName Microsoft.PowerShell.Management\Remove-Item
        .ForwardHelpCategory Cmdlet
    
        #>
    }
    
    Set-Alias -Name rm -Value Remove-ItemProxy -Option AllScope