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.
First try:
function rm -rf() {
rm -r -fo
}
Second try:
Set-Alias rm -rf "rm -r -fo"
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