480 votes

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

Quel est le moyen le plus simple de supprimer de force un répertoire et tous ses sous-répertoires dans PowerShell ? J'utilise PowerShell V2 sous Windows 7.

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

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

J'ai vu plusieurs exemples qui utilisent Get-ChildItem et l'envoyer à Remove-Item mais les exemples suppriment généralement un ensemble de fichiers en fonction d'un filtre, et non le répertoire entier.

Je cherche le moyen le plus propre de faire sauter un répertoire entier, des fichiers et des répertoires enfants, sans générer de messages d'avertissement pour l'utilisateur et en utilisant le moins de code possible. Une solution en une seule ligne serait la bienvenue si elle est facile à comprendre.

2 votes

Powershell, je sais, mais RD /S /Q

0 votes

0 votes

Je ne pense pas que ce soit un doublon. J'ai examiné la question 1667145 avant de la poster. Il s'agit de savoir pourquoi PowerShell ne définit pas correctement le paramètre bool Recurse lors de l'appel de l'implémentation de la méthode Remove-Item d'un fournisseur PowerShell personnalisé. Je demandais le comportement de Remove-Item en relation avec le fournisseur de système de fichiers intégré.

4voto

Michael Litwak Points 191

La suppression d'une arborescence de dossiers entière fonctionne parfois et échoue parfois avec des erreurs "Directory not empty". Si l'on tente ensuite de vérifier si le dossier existe toujours, des erreurs "Accès refusé" ou "Accès non autorisé" peuvent se produire. Je ne sais pas pourquoi cela se produit, bien que l'on puisse trouver une explication dans les documents suivants ce message de 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 délais. La méthode suivante 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 de Microsoft TechNet Utilisation des 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 peut être résolu 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é ci-dessous).

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

0 votes

Ver cette réponse que David Faivre a mentionné dans sa réponse ci-dessous, pour une explication de la raison pour laquelle la suppression de répertoire échoue parfois, et un remède plus sophistiqué.

3voto

Peter McEvoy Points 1653

J'ai adopté une autre approche inspirée par @john-rees ci-dessus - notamment lorsque son approche a commencé à échouer pour moi à un moment donné. En fait, il s'agit de récurer la sous-arborescence et de trier les fichiers en fonction de leur longueur de chemin - en les supprimant 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 de -LiteralPath, voici un autre problème qui peut se poser à vous : https://superuser.com/q/212808

3voto

David Faivre Points 705

Il semble y avoir des problèmes lorsque Remove-Item -Force -Recurse peut échouer par intermittence sous Windows car le système de fichiers sous-jacent est asynchrone. Cette réponse semble y répondre. L'utilisateur a également été activement impliqué dans l'équipe Powershell sur GitHub .

2voto

Une autre astuce utile :

Si vous trouvez beaucoup de fichiers avec une convention de nom identique ou similaire (comme le fichier mac avec le nom préfixe point... cette fameuse 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 actuel, et tous les fichiers avec les mêmes circonstances dans les autres dossiers de ce répertoire aussi. Soyez-en conscient lorsque vous l'utilisez :D

0 votes

Pourquoi ne pas utiliser rm -rf .* ? Je n`ai pas de powershell pour tester, mais je pense que ça va marcher.

1 votes

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.

0 votes

Au fait, pour supprimer les fichiers qui commencent par un point (comme les fichiers mac) mais qui ont une propriété cachée, vous pouvez utiliser : ls -r -h .* | rm

2voto

steve simon Points 41

Pour supprimer le contenu complet, y compris la structure du dossier, utilisez

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

El -recurse ajouté à remove-item garantit que les invites interactives sont désactivées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X