¿Cómo eliminar recursivamente un directorio completo con PowerShell 2.0?

308

¿Cuál es la forma más sencilla de eliminar forzosamente un directorio y todos sus subdirectorios en PowerShell? Estoy usando PowerShell V2 en Windows 7.

He aprendido de varias fuentes que el comando más obvio Remove-Item $targetDir -Recurse -Forceno funciona correctamente. Esto incluye una declaración en la ayuda en línea de PowerShell V2 (que se encuentra usando Get-Help Remove-Item -Examples) que dice:

... Debido a que el parámetro Recurse en este cmdlet es defectuoso, el comando usa el cmdlet Get-Childitem para obtener los archivos deseados, y usa el operador de canalización para pasarlos al cmdlet Remove-Item ...

He visto varios ejemplos que usan Get-ChildItem y lo canalizan a Remove-Item , pero los ejemplos generalmente eliminan algunos conjuntos de archivos basados ​​en un filtro, no todo el directorio.

Estoy buscando la forma más limpia de eliminar un directorio completo, archivos y directorios secundarios, sin generar ningún mensaje de advertencia del usuario con la menor cantidad de código. Una frase sería buena si es fácil de entender.

Matt Spradley
fuente
2
PowerShell, lo sé, peroRD /S /Q
Rubens Farias
posible duplicado: stackoverflow.com/questions/1667145/…
Rubens Farias
No creo que sea un duplicado. Revisé 1667145 antes de publicar. Se pregunta por qué PowerShell no está configurando el parámetro booleano Recurse correctamente cuando se llama a la implementación del método Remove-Item de un proveedor de PowerShell personalizado. Estaba preguntando sobre el comportamiento de Eliminar elemento en relación con el proveedor del sistema de archivos incorporado.
Matt Spradley
2
"RD / S / Q" no parece funcionar en PowerShell, dice "Remove-Item: no se puede encontrar un parámetro posicional que acepte el argumento '/ q'".
BrainSlugs83
55
rdes un alias para Remove-Itemen powershell. cmd /c "rd /s /q"funciona, sin embargo.
codekaizen

Respuestas:

511
Remove-Item -Recurse -Force some_dir

de hecho funciona como se anuncia aquí.

rm -r -fo some_dir

son alias abreviados que también funcionan.

Según tengo entendido, el -Recurseparámetro simplemente no funciona correctamente cuando intentas eliminar un conjunto filtrado de archivos de forma recursiva. Para matar un solo directorio y todo lo que está debajo parece funcionar bien.

Joey
fuente
55
Creo que es correcto. Recibía el mensaje "No se puede eliminar el elemento en 'algún directorio' porque está en uso". error y asumí que era un problema con el algoritmo de recursión y busqué una solución alternativa. Resulta que tuve un proceso que activé anteriormente en el script que funcionaba en el directorio de destino. Cuando se cambia la secuencia de comandos para esperar el otro proceso, funciona el comando "Eliminar-Elemento-Recursar-Fuerza". Siempre mire en el espejo primero :)
Matt Spradley
15
Descubrí que necesito ejecutar esto dos veces cuando se ejecuta en un directorio que contiene subdirectorios. La primera vez, habrá muchos errores de "El directorio no está vacío". La segunda vez, se completa sin errores.
Kristopher Johnson
55
Kristopher Johnson, obtengo errores similares con diversas herramientas en Windows 7. Parece que la llamada de eliminación regresa antes de que un archivo o carpeta se elimine, lo que a veces causa problemas. Esto parece suceder en Explorer, Far, cmd y PowerShell.
Joey
2
@Joey "Parece que la llamada de eliminación regresa antes de que un archivo o carpeta se elimine, causando problemas a veces". -> Para aclaración: la carpeta principal no se eliminará y se obtiene el siguiente error: "[carpeta principal] no se puede eliminar porque no está vacía". Veo que esto sucede constantemente en unidades de red (lentas). La única solución es la anterior: cmd /c rdcomo se indica a continuación.
Davor Josipovic el
66
¿Qué pasa con los errores "El directorio no está vacío"? serverfault.com/questions/199921/powershell-remove-force Quizás sea mejor get-childitem * -include * .csv -recurse | remove-item No lo sé. Ver stackoverflow.com/a/1668471/206730
Kiquenet
39

Solía:

rm -r folderToDelete

Esto funciona para mí como un encanto (lo robé de Ubuntu).

Tuan Jinn
fuente
¿No requiere eso cygwin, git o alguna otra herramienta que pueda simular un shell bash en Windows?
Pete
19
@Pete, no, no requiere nada más que PowerShell. rmes un alias para Remove-Itemla configuración predeterminada de PowerShell. Verifique la salida de Get-Alias rmpara más detalles. Se -restá aprovechando el comportamiento de coincidencia parcial de PowerShell en los parámetros. Como Remove-Itemsolo tiene un parámetro que comienza con una 'r' -Recurse, -rcoincide con eso. Por lo tanto, la siguiente todo funcionará de la misma: rm -r, rm -re, Remove-Item -Recurse. (Nota que ni rm -rftampoco rm -r -fva a funcionar, pero rm -r -fo. Lo harán -rfcoincide con ningún parámetro y -fcoincide con más de uno.)
chwarr
1
Qué hay sobre eso. El alias de Powershell rm para "Remove-Item -Recurse -Force some_dir" funciona mejor que usar directamente remove-item. Recibí los mismos errores "No se puede eliminar el elemento en 'algún directorio'. ¡Cambio de remove-item a rm -r sin errores !?
Greg
Interesante. Tengo herramientas cygwin en mi caja, lo intenté rm -rf foldery, por supuesto, falló. Inicialmente rechacé la respuesta (porque decía Ubuntu). Gracias al comentario de @chwarr, lo probé sin el fy tomó el alias en lugar de rm binary. Desearía que Tuan actualizara su fuente (no estoy seguro si Tuan sabía que era un alias o realmente pensaba que era el rm de Unix ;-)
Joshua Ball el
2
Tal vez sea porque uso el en -Rlugar de -r(aunque, por lo que sé, PowerShell es como el resto de Windows, no distingue entre mayúsculas y minúsculas, por lo tanto, no debería hacer una diferencia), pero recibí un error de que las carpetas que estoy tratando de eliminar son no vacío.
rbaleksandar
25

Al eliminar archivos de forma recursiva usando un simple Remove-Item "folder" -Recurse, a veces veo un error intermitente:[folder] cannot be removed because it is not empty.

Esta respuesta intenta evitar ese error eliminando individualmente los archivos.

function Get-Tree($Path,$Include='*') { 
    @(Get-Item $Path -Include $Include -Force) + 
        (Get-ChildItem $Path -Recurse -Include $Include -Force) | 
        sort pspath -Descending -unique
} 

function Remove-Tree($Path,$Include='*') { 
    Get-Tree $Path $Include | Remove-Item -force -recurse
} 

Remove-Tree some_dir

Un detalle importante es la clasificación de todos los elementos pspath -Descendingpara que las hojas se eliminen antes que las raíces. La clasificación se realiza según el pspathparámetro, ya que tiene más posibilidades de trabajar para proveedores distintos del sistema de archivos. los-Include parámetro es solo una conveniencia si desea filtrar los elementos para eliminar.

Se divide en dos funciones, ya que me resulta útil ver lo que estoy a punto de eliminar ejecutando

Get-Tree some_dir | select fullname
John Rees
fuente
1
Al resolver un problema usando PowerShell en los scripts de compilación de TFS, resultó ser la respuesta correcta.
rcabr
Esta es la solución para mí también. ¡Ten algunos puntos, mi buen hombre!
Jammer
Trabajó para mi. No pude obtener la eliminación recursiva del contenido de una carpeta, pero su solución funcionó para mí. gracias
SheldonH
Esta es una solución muy robusta
Max Young
No estoy seguro de por qué la respuesta aceptada tiene tantos votos: personalmente sigo recibiendo errores intermitentes al usar remove-item -recursePowershell v5, por lo que esta solución es la mejor para mí.
JonoB
13
rm -r ./folder -Force    

...trabajó para mi

stevethecollier
fuente
11

Prueba este ejemplo. Si el directorio no existe, no se genera ningún error. Es posible que necesite PowerShell v3.0.

remove-item -path "c:\Test Temp\Test Folder" -Force -Recurse -ErrorAction SilentlyContinue
Steve
fuente
7

Use el comando DOS de la vieja escuela:

rd /s <dir>
Peter Mortensen
fuente
Si esto es parte de un script, tendría que usar /q(Modo silencioso, no pregunte si está bien para eliminar un árbol de directorios con / S) también.
wildeyes
6

Por alguna razón, la respuesta de John Rees a veces no funcionó en mi caso. Pero me llevó en la siguiente dirección. Primero trato de eliminar el directorio de forma recursiva con la opción buggy -recurse. Luego desciendo a cada subdirectorio que queda y elimino todos los archivos.

function Remove-Tree($Path)
{ 
    Remove-Item $Path -force -Recurse -ErrorAction silentlycontinue

    if (Test-Path "$Path\" -ErrorAction silentlycontinue)
    {
        $folders = Get-ChildItem -Path $Path –Directory -Force
        ForEach ($folder in $folders)
        {
            Remove-Tree $folder.FullName
        }

        $files = Get-ChildItem -Path $Path -File -Force

        ForEach ($file in $files)
        {
            Remove-Item $file.FullName -force
        }

        if (Test-Path "$Path\" -ErrorAction silentlycontinue)
        {
            Remove-Item $Path -force
        }
    }
}
jdoose
fuente
¿Puedes reproducir el error al ejecutar mis funciones? Me gustaría saber para poder mejorarlos.
John Rees
Lo sentimos, no recuerdo la configuración exacta. : / Creo que fue cuando participaron varios subdirectorios. Sucedió que la llamada a "Remove-Item -force -recurse" no eliminó todos los archivos y en ese caso el último Remove-Tree falló porque el directorio no estaba vacío. Es por eso que se me ocurrió la nueva solución para probar primero la versión incorporada con errores (-force) y luego descender manualmente a cada directorio y eliminar "manualmente" lo que queda. Esta versión está en uso regularmente y hasta ahora está funcionando. La única causa que falló fue cuando un programa todavía tiene un identificador para un directorio.
jdoose
5

Para evitar los errores "El directorio no está vacío" de la respuesta aceptada, simplemente use el viejo comando DOS como se sugirió anteriormente. La sintaxis completa de PS lista para copiar y pegar es:

& cmd.exe /c rd /S /Q $folderToDelete
Dejan
fuente
3
¿Todavía da el error "El directorio no está vacío" para las carpetas?
Oncel Umut TURER
2

Tomé otro enfoque inspirado por @ john-rees arriba, especialmente cuando su enfoque comenzó a fallar para mí en algún momento. Básicamente, repita el subárbol y clasifique los archivos por su longitud de ruta: elimine del más largo al más corto

Get-ChildItem $tfsLocalPath -Recurse |  #Find all children
    Select-Object FullName,@{Name='PathLength';Expression={($_.FullName.Length)}} |  #Calculate the length of their path
    Sort-Object PathLength -Descending | #sort by path length descending
    %{ Get-Item -LiteralPath $_.FullName } | 
    Remove-Item -Force

Con respecto a la magia -LiteralPath, aquí hay otro gotchya que puede estar golpeándote: https://superuser.com/q/212808

Peter McEvoy
fuente
2
del <dir> -Recurse -Force # I prefer this, short & sweet

O

remove-item <dir> -Recurse -Force

Si tienes un directorio enorme, entonces lo que suelo hacer es

while (dir | where name -match <dir>) {write-host deleting; sleep -s 3}

Ejecute esto en otro terminal de PowerShell y se detendrá cuando termine.

Gajendra D Ambi
fuente
Admito que su idea con el monitoreo puede ser útil, pero es apenas diferente de simplemente imprimir un mensaje una vez que está terminado, y en caso de que haya algún problema al detener el elemento Eliminar, su ciclo nunca terminará.
Raúl Salinas-Monteagudo
@ RaúlSalinas-Monteagudo es cierto, pero definitivamente es para un caso de uso desatendido. Tiene que ser lo suficientemente pequeño para que alguien pueda recordarlo y escribir sobre la marcha y no ejecutar un sofisticado archivo .ps1 en solo un directorio.
Gajendra D Ambi
2

Eliminar un árbol de carpetas completo a veces funciona y a veces falla con los errores "Directorio no vacío". Posteriormente, intentar verificar si la carpeta aún existe puede provocar errores de "Acceso denegado" o "Acceso no autorizado". No sé por qué sucede esto, aunque se puede obtener una idea de esta publicación de StackOverflow .

He podido solucionar estos problemas especificando el orden en que se eliminan los elementos dentro de la carpeta y agregando retrasos. Lo siguiente me funciona bien:

# First remove any files in the folder tree
Get-ChildItem -LiteralPath $FolderToDelete -Recurse -Force | Where-Object { -not ($_.psiscontainer) } | Remove-Item Force

# Then remove any sub-folders (deepest ones first).    The -Recurse switch may be needed despite the deepest items being deleted first.
ForEach ($Subfolder in Get-ChildItem -LiteralPath $FolderToDelete -Recurse -Force | Select-Object FullName, @{Name="Depth";Expression={($_.FullName -split "\\").Count}} | Sort-Object -Property @{Expression="Depth";Descending=$true}) { Remove-Item -LiteralPath $Subfolder.FullName -Recurse -Force }

# Then remove the folder itself.  The -Recurse switch is sometimes needed despite the previous statements.
Remove-Item -LiteralPath $FolderToDelete -Recurse -Force

# Finally, give Windows some time to finish deleting the folder (try not to hurl)
Start-Sleep -Seconds 4

Un artículo de Microsoft TechNet Uso de propiedades calculadas en PowerShell me ayudó a obtener una lista de subcarpetas ordenadas por profundidad.

Se pueden resolver problemas de confiabilidad similares con RD / S / Q ejecutando DEL / F / S / Q antes de RD / S / Q y ejecutando el RD por segunda vez si es necesario, idealmente con una pausa en el medio (es decir, usando ping como se muestra abajo).

DEL /F /S /Q "C:\Some\Folder\to\Delete\*.*" > nul
RD /S /Q "C:\Some\Folder\to\Delete" > nul
if exist "C:\Some\Folder\to\Delete"  ping -4 -n 4 127.0.0.1 > nul
if exist "C:\Some\Folder\to\Delete"  RD /S /Q "C:\Some\Folder\to\Delete" > nul
MikeOnline
fuente
1

Muy simple:

remove-item -path <type in file or directory name>, press Enter
DusanV
fuente
También debe ofrecer un ejemplo de ejecución.
indivisible
1

Otro truco útil:

Si encuentra una gran cantidad de archivos con la misma convención de nombre o similar (como un archivo mac con el nombre de prefijo de punto ... esa famosa extracción de archivos), puede eliminarlos fácilmente con una sola línea de PowerShell como esta:

ls -r .* | rm

Esta línea eliminará todos los archivos con un punto al principio del nombre dentro del directorio actual, y todos los archivos con las mismas circunstancias dentro de otras carpetas dentro de este directorio también. Tenga cuidado al usarlo. :RE

Daniel Alberto Lepe Ayala
fuente
¿Por qué no usar rm -rf .*? No tengo PowerShell para probar, pero creo que funcionará.
Vini.g.fer
1
Es fácil; si simplemente elimina "| rm" del comando, puede ver un panorama completo de lo que va a eliminar, después de estar seguro, puede completar el comando.
Daniel Alberto Lepe Ayala
Por cierto, para quitar los archivos que empiecen con punto, (como los de mac) pero que tengan propiedad de oculto, puedes usar: ls -r -h. * | rm
Daniel Alberto Lepe Ayala
1

Para eliminar el contenido completo, incluida la estructura de carpetas, use

get-childitem $dest -recurse | foreach ($_) {remove-item $_.fullname -recurse}

El -recurseagregado a remove-itemgarantiza que las solicitudes interactivas estén deshabilitadas.

Steve Simon
fuente
-1
$users = get-childitem \\ServerName\c$\users\ | select -ExpandProperty name

foreach ($user in $users)

{
remove-item -path "\\Servername\c$\Users\$user\AppData\Local\Microsoft\Office365\PowerShell\*" -Force -Recurse
Write-Warning "$user Cleaned"
}

Escribió lo anterior para limpiar algunos archivos de registro sin eliminar el directorio principal y ¡esto funciona perfectamente!

Tom Stevenson
fuente
-2
rm -r <folder_name>
c:\>rm -r "my photos"
usuario3008
fuente
1
Por favor, explique eso para que otros puedan aprender de su respuesta
Nico Haase