Comment supprimer récursivement un répertoire entier avec PowerShell 2.0?

308

Quelle est la façon la plus simple de supprimer de force un répertoire et tous ses sous-répertoires dans PowerShell? J'utilise PowerShell V2 dans Windows 7.

J'ai appris de plusieurs sources que la commande la plus évidente,, Remove-Item $targetDir -Recurse -Forcene fonctionne pas correctement. Cela inclut une déclaration dans l'aide en ligne de PowerShell V2 (trouvée à l'aide Get-Help Remove-Item -Examples) qui indique:

... Étant donné que le paramètre Recurse de cette applet de commande est défectueux, la commande utilise l'applet de commande Get-Childitem pour obtenir les fichiers souhaités et utilise l'opérateur de pipeline pour les transmettre à l'applet de commande Remove-Item ...

J'ai vu divers exemples qui utilisent Get-ChildItem et le redirigent vers Remove-Item , mais les exemples suppriment généralement certains ensembles de fichiers basés sur un filtre, pas le répertoire entier.

Je recherche le moyen le plus propre de supprimer un répertoire entier, des fichiers et des répertoires enfants, sans générer de messages d'avertissement utilisateur en utilisant le moins de code possible. Un one-liner serait bien s'il est facile à comprendre.

Matt Spradley
la source
2
PowerShell, je sais, maisRD /S /Q
Rubens Farias
doublon possible: stackoverflow.com/questions/1667145/…
Rubens Farias
Je ne pense pas que ce soit un doublon. J'ai passé en revue 1667145 avant de poster. Il demande pourquoi PowerShell ne définit pas correctement le paramètre booléen Recurse lors de l'appel de l'implémentation de la méthode Remove-Item d'un fournisseur PowerShell personnalisé. Je posais des questions sur le comportement de Remove-Item en ce qui concerne le fournisseur de système de fichiers intégré.
Matt Spradley
2
"RD / S / Q" ne semble pas fonctionner dans PowerShell - dit "Remove-Item: Impossible de trouver un paramètre positionnel qui accepte l'argument '/ q'."
BrainSlugs83
5
rdest un alias pour Remove-Itemdans PowerShell. cmd /c "rd /s /q"fonctionne, cependant.
codekaizen

Réponses:

511
Remove-Item -Recurse -Force some_dir

fonctionne en effet comme annoncé ici.

rm -r -fo some_dir

sont des alias raccourcis qui fonctionnent aussi.

Pour autant que je l'ai compris, le -Recurseparamètre ne fonctionne tout simplement pas correctement lorsque vous essayez de supprimer un ensemble de fichiers filtrés de manière récursive. Pour tuer un seul répertoire et tout ce qui se trouve en dessous, cela semble bien fonctionner.

Joey
la source
5
Je pense que vous avez raison. J'obtenais un "Impossible de supprimer l'élément dans 'un certain répertoire' car il est en cours d'utilisation." erreur et a supposé que c'était un problème avec l'algorithme de récursivité et est allé chercher une solution de contournement. Il s'avère que j'avais un processus que j'ai déclenché plus tôt dans le script qui fonctionnait dans le répertoire cible. Une fois le script modifié pour attendre l'autre processus, la commande "Remove-Item -Recurse -Force" fonctionne. Regardez toujours dans le miroir en premier :)
Matt Spradley
15
J'ai constaté que je dois l'exécuter deux fois lorsqu'il est exécuté sur un répertoire qui contient des sous-répertoires. La première fois, il y aura beaucoup d'erreurs "Le répertoire n'est pas vide". La deuxième fois, il se termine sans erreur.
Kristopher Johnson
5
Kristopher Johnson, j'obtiens des erreurs similaires avec différents outils sur Windows 7. Il semble que l'appel de suppression retourne plus tôt qu'un fichier ou un dossier est réellement supprimé, ce qui provoque parfois des problèmes. Cela semble se produire dans Explorer, Far, cmd et PowerShell.
Joey
2
@Joey "Il semble que l'appel de suppression soit retourné avant qu'un fichier ou un dossier ne soit réellement supprimé, ce qui provoque parfois des problèmes." -> Pour plus de précision: le dossier parent ne sera pas supprimé et on obtient l'erreur suivante: "[le dossier parent] ne peut pas être supprimé car il n'est pas vide." Je vois cela se produire constamment sur des disques en réseau (lents). La seule solution est l'ancienne: cmd /c rdcomme indiqué ci-dessous.
Davor Josipovic
6
Qu'en est-il des erreurs "Le répertoire n'est pas vide"? serverfault.com/questions/199921/powershell-remove-force Peut-être mieux get-childitem * -include * .csv -recurse | remove-item je ne sais pas. Voir stackoverflow.com/a/1668471/206730
Kiquenet
39

J'ai utilisé:

rm -r folderToDelete

Cela fonctionne pour moi comme un charme (je l'ai volé à Ubuntu).

Tuan Jinn
la source
Cela ne nécessite-t-il pas cygwin, git ou un autre outil capable de simuler un shell bash sous Windows?
Pete
19
@Pete, non, il ne nécessite rien d'autre que PowerShell. rmest un alias pour Remove-Itemdans la configuration par défaut de PowerShell. Vérifiez la sortie de Get-Alias rmpour plus de détails. Le -rtire parti du comportement de correspondance partielle de PowerShell sur les paramètres. Étant donné Remove-Itemque seul le paramètre qui commence par un «r» -Recurse, -rcorrespond à cela. Ainsi, ce qui suit tout fonctionnera de la même: rm -r, rm -re, Remove-Item -Recurse. (Notez que ni rm -rfni rm -r -fne fonctionnera, mais fonctionnera rm -r -fo. -rfNe correspond à aucun paramètre et -fcorrespond à plus d'un.)
chwarr
1
Et ça. L'alias RM Powershell pour "Remove-Item -Recurse -Force some_dir" fonctionne mieux que d'utiliser directement remove-item. J'ai reçu les mêmes erreurs "Impossible de supprimer l'élément dans 'un répertoire'. Je passe de remove-item à rm -r sans erreur!?
Greg
Intéressant. J'ai des outils cygwin sur ma boîte, et j'avais essayé rm -rf folderet bien sûr, cela a échoué. Au départ, j'ai voté contre la réponse (car elle disait Ubuntu). Grâce au commentaire de @chwarr, je l'ai essayé sans le fet il a repris l'alias plutôt que le binaire rm. J'aimerais que Tuan mette à jour sa source (je ne sais pas si Tuan savait que c'était un alias ou pensait vraiment que c'était la version unix ;-)
Joshua Ball
2
C'est peut-être parce que j'utilise le -Rau lieu de -r(bien que pour autant que je sache, PowerShell est comme le reste de Windows ne respecte pas la casse, donc cela ne devrait pas faire de différence), mais j'ai eu une erreur que les dossiers que j'essaie de supprimer sont pas vide.
rbaleksandar
25

Lors de la suppression récursive de fichiers à l'aide d'un simple, Remove-Item "folder" -Recurseje vois parfois une erreur intermittente:[folder] cannot be removed because it is not empty.

Cette réponse tente d'éviter cette erreur en supprimant individuellement les fichiers.

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 détail important est le tri de tous les éléments avec pspath -Descendingpour que les feuilles soient supprimées avant les racines. Le tri est effectué sur le pspathparamètre car cela a plus de chances de fonctionner pour des fournisseurs autres que le système de fichiers. le-Include paramètre n'est qu'une commodité si vous souhaitez filtrer les éléments à supprimer.

Il est divisé en deux fonctions car je trouve utile de voir ce que je vais supprimer en exécutant

Get-Tree some_dir | select fullname
John Rees
la source
1
Lors de la résolution d'un problème à l'aide de PowerShell dans les scripts de génération TFS, cela s'est avéré être la bonne réponse.
rcabr
C'est aussi la solution pour moi. Ayez quelques points mon bonhomme!
Jammer
A travaillé pour moi. Je n'ai pas pu obtenir la suppression récursive du contenu d'un dossier, mais votre solution a fonctionné pour moi. merci
SheldonH
Ceci est une solution très robuste
Max Young
Je ne sais pas pourquoi la réponse acceptée a autant de votes - Personnellement, je reçois toujours des erreurs intermittentes remove-item -recursedans Powershell v5, donc cette solution est la meilleure pour moi.
JonoB
13
rm -r ./folder -Force    

... a travaillé pour moi

stevethecollier
la source
11

Essayez cet exemple. Si le répertoire n'existe pas, aucune erreur n'est générée. Vous devrez peut-être PowerShell v3.0.

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

Utilisez la commande DOS old-school:

rd /s <dir>
Peter Mortensen
la source
Si cela fait partie d'un script, vous devrez également utiliser /q(mode silencieux, ne demandez pas si vous pouvez supprimer une arborescence de répertoires avec / S).
Wildeyes
6

Pour une raison quelconque, la réponse de John Rees n'a parfois pas fonctionné dans mon cas. Mais cela m'a conduit dans la direction suivante. J'essaie d'abord de supprimer le répertoire récursivement avec l'option buggy -recurse. Ensuite, je descends dans chaque sous-répertoire restant et je supprime tous les fichiers.

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
la source
Pouvez-vous reproduire l'erreur lors de l'exécution de mes fonctions? J'aimerais savoir pour pouvoir les améliorer.
John Rees
Désolé, je ne me souviens pas du paramètre exact. : / Je pense que c'était lorsque plusieurs sous-répertoires étaient impliqués. Il est arrivé que l'appel à "Remove-Item -force -recurse" n'ait pas supprimé tous les fichiers et, dans ce cas, le dernier Remove-Tree a échoué car le répertoire n'était pas vide. C'est pourquoi j'ai trouvé la nouvelle solution pour essayer d'abord la version intégrée du buggy (-force), puis descendre manuellement dans chaque répertoire et supprimer "manuellement" ce qui reste. Cette version est utilisée régulièrement et jusqu'à présent elle fonctionne. La seule cause de son échec était lorsqu'un programme contient toujours un handle vers un répertoire.
jdoose
5

Pour éviter les erreurs "Le répertoire n'est pas vide" de la réponse acceptée, utilisez simplement la bonne vieille commande DOS comme suggéré précédemment. La syntaxe PS complète prête pour le copier-coller est:

& cmd.exe /c rd /S /Q $folderToDelete
Dejan
la source
3
Il donne toujours l'erreur "Le répertoire n'est pas vide" pour les dossiers!?
Oncel Umut TURER
2

J'ai pris une autre approche inspirée de @ john-rees ci-dessus - en particulier lorsque son approche a commencé à échouer pour moi à un moment donné. Récapitulez les sous-arbres et triez les fichiers en fonction de leur longueur de chemin - supprimez du plus long au plus court

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

En ce qui concerne la magie -LiteralPath, voici un autre gotchya qui pourrait vous frapper: https://superuser.com/q/212808

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

OU

remove-item <dir> -Recurse -Force

Si vous avez un énorme répertoire, ce que je fais habituellement est

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

Exécutez-le sur un autre terminal PowerShell et il s'arrêtera une fois terminé.

Gajendra D Ambi
la source
J'admets que votre idée avec la surveillance peut être utile, mais c'est à peine différent de simplement imprimer un message une fois qu'il est terminé, et au cas où il y aurait un problème pour arrêter le Remove-Item, votre boucle ne se terminera jamais.
Raúl Salinas-Monteagudo
@ RaúlSalinas-Monteagudo true mais c'est certainement pour un scénario de cas d'utilisation prod ou sans surveillance. Il doit être suffisamment petit pour que quelqu'un se souvienne et tape sur le pouce et ne pas exécuter un fichier .ps1 sophistiqué dans un seul répertoire.
Gajendra D Ambi
2

La suppression d'une arborescence de dossiers entière fonctionne parfois et échoue parfois avec des erreurs «Répertoire non vide». Par la suite, essayer de vérifier si le dossier existe toujours peut entraîner des erreurs «Accès refusé» ou «Accès non autorisé». Je ne sais pas pourquoi cela se produit, bien que certaines informations puissent être tirées de cette publication StackOverflow .

J'ai pu contourner ces problèmes en spécifiant l'ordre dans lequel les éléments du dossier sont supprimés et en ajoutant des retards. Ce qui suit fonctionne bien pour moi:

# 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 article Microsoft TechNet utilisant les propriétés calculées dans PowerShell m'a été utile pour obtenir une liste de sous-dossiers triés par profondeur.

Des problèmes de fiabilité similaires avec RD / S / Q peuvent être résolus en exécutant DEL / F / S / Q avant RD / S / Q et en exécutant le RD une deuxième fois si nécessaire - idéalement avec une pause entre les deux (c'est-à-dire en utilisant ping comme indiqué au dessous de).

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
la source
1

Vraiment simple:

remove-item -path <type in file or directory name>, press Enter
DusanV
la source
Vous devriez également proposer un exemple d'exécution.
indivisible
1

Une autre astuce utile:

Si vous trouvez beaucoup de fichiers avec une convention de nom identique ou similaire (comme un fichier mac avec un nom de préfixe de point ... ce fameux pulltion de fichier), vous pouvez facilement les supprimer avec une seule ligne du PowerShell comme ceci:

ls -r .* | rm

Cette ligne va supprimer tous les fichiers avec un point au début du nom dans le répertoire courant, ainsi que tous les fichiers ayant les mêmes circonstances dans d'autres dossiers de ce répertoire. Soyez conscient lors de son utilisation. :RÉ

Daniel Alberto Lepe Ayala
la source
Pourquoi ne pas utiliser rm -rf .*? Je n'ai pas de PowerShell à tester, mais je pense que cela fonctionnera.
Vini.g.fer
1
C'est facile; si vous supprimez simplement le "| rm" de la commande, vous pouvez voir un panorama complet de ce que vous allez supprimer, après avoir été sûr, vous pouvez terminer la commande.
Daniel Alberto Lepe Ayala
Par 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

Pour supprimer le contenu complet, y compris la structure des dossiers, utilisez

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

L' -recurseajout à remove-itemgarantit que les invites interactives sont désactivées.

steve simon
la source
-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"
}

A écrit ce qui précède pour nettoyer certains fichiers journaux sans supprimer le répertoire parent et cela fonctionne parfaitement!

Tom Stevenson
la source
-2
rm -r <folder_name>
c:\>rm -r "my photos"
user3008
la source
1
Veuillez expliquer cela de manière à ce que d'autres puissent apprendre de votre réponse
Nico Haase