Come eliminare in modo ricorsivo un'intera directory con PowerShell 2.0?


308

Qual è il modo più semplice per eliminare forzatamente una directory e tutte le sue sottodirectory in PowerShell? Sto usando PowerShell V2 in Windows 7.

Ho appreso da diverse fonti che il comando più ovvio Remove-Item $targetDir -Recurse -Force, non funziona correttamente. Ciò include una dichiarazione nella guida in linea di PowerShell V2 (trovata usando Get-Help Remove-Item -Examples) che afferma:

... Poiché il parametro Recurse in questo cmdlet è errato, il comando utilizza il cmdlet Get-Childitem per ottenere i file desiderati e utilizza l'operatore della pipeline per passarli al cmdlet Remove-Item ...

Ho visto vari esempi che usano Get-ChildItem e lo inoltrano a Remove-Item , ma gli esempi rimuovono di solito un set di file basato su un filtro, non l'intera directory.

Sto cercando il modo più pulito per eliminare un'intera directory, file e directory secondarie, senza generare alcun messaggio di avviso dell'utente utilizzando la minima quantità di codice. Un one-liner sarebbe carino se fosse facile da capire.


2
PowerShell, lo so, maRD /S /Q
Rubens Farias,


Non penso sia un duplicato. Ho esaminato 1667145 prima di pubblicare. Si sta chiedendo perché PowerShell non stia impostando correttamente il parametro bool Recurse quando si chiama l'implementazione del metodo Remove-Item di un provider PowerShell personalizzato. Stavo chiedendo del comportamento Rimuovi-Articolo in relazione al provider di file system integrato.
Matt Spradley,

2
"RD / S / Q" non sembra funzionare in PowerShell - dice "Rimuovi elemento: Impossibile trovare un parametro posizionale che accetta l'argomento '/ q'."
BrainSlugs83

5
rdè un alias per Remove-Itemin PowerShell. cmd /c "rd /s /q"funziona, però.
codekaizen,

Risposte:


511
Remove-Item -Recurse -Force some_dir

funziona davvero come pubblicizzato qui.

rm -r -fo some_dir

sono alias di stenografia che funzionano anche.

Per quanto ho capito, il -Recurseparametro non funziona correttamente quando si tenta di eliminare ricorsivamente un set di file filtrati. Per aver ucciso una sola directory e tutto quanto sotto sembra funzionare bene.


5
Penso che tu abbia ragione. Stavo ottenendo un messaggio "Impossibile rimuovere l'elemento in" alcune directory "perché è in uso." errore e supponevo che fosse un problema con l'algoritmo di ricorsione e andò alla ricerca di una soluzione alternativa. Si scopre che ho avuto un processo che avevo avviato in precedenza nello script che funzionava nella directory di destinazione. Quando lo script è stato modificato per attendere l'altro processo, il comando "Rimuovi-Item -Recurse -Force" funziona. Guarda sempre prima allo specchio :)
Matt Spradley,

15
Ho scoperto che devo eseguirlo due volte quando eseguito su una directory che contiene sottodirectory. La prima volta, ci saranno molti errori "La directory non è vuota". La seconda volta, si completa senza errori.
Kristopher Johnson,

5
Kristopher Johnson, ricevo errori simili con vari strumenti su Windows 7. Sembra che la chiamata di cancellazione ritorni prima che un file o una cartella venga effettivamente rimosso, causando problemi a volte. Questo sembra accadere in Explorer, Far, cmd e PowerShell.
Joey,

2
@Joey "Sembra che la chiamata di eliminazione ritorni prima che un file o una cartella venga effettivamente rimossa, causando problemi a volte." -> Per chiarimenti: la cartella principale non verrà eliminata e si otterrà il seguente errore: "[cartella principale] non può essere rimossa perché non è vuota." Vedo che ciò accade costantemente su unità di rete (lente). L'unica soluzione è quella vecchia: cmd /c rdcome indicato di seguito.
Davor Josipovic

6
Che dire degli errori "La directory non è vuota"? serverfault.com/questions/199921/powershell-remove-force Forse meglio get-childitem * -include * .csv -recurse | remove-item Non lo so. Vedere stackoverflow.com/a/1668471/206730
Kiquenet

39

Ero solito:

rm -r folderToDelete

Questo funziona per me come un incantesimo (l'ho rubato da Ubuntu).


Non è necessario cygwin, git o qualche altro strumento in grado di simulare una shell bash su Windows?
Pete,

19
@Pete, no, non richiede altro che PowerShell. rmè un alias per Remove-Itemnella configurazione predefinita di PowerShell. Controlla l'output di Get-Alias rmper maggiori dettagli. La -rsta prendendo vantaggio del comportamento corrispondenza parziale di PowerShell sui parametri. Poiché Remove-Itemha solo un parametro che inizia con una 'r' -Recurse, -rcorrisponde a quello. Così, il seguente tutto funzionerà lo stesso: rm -r, rm -re, Remove-Item -Recurse. (Nota che né funzionerà rm -rfrm -r -ffunzionerà, ma rm -r -fonon -rfcorrisponderà a nessun parametro e -fcorrisponderà a più di uno.)
chwarr,

1
Che ne dici di quello. L'alias di Powershell rm per "Remove-Item -Recurse -Force some_dir" funziona meglio rispetto all'utilizzo diretto di remove-item. Ho ricevuto gli stessi errori "Impossibile rimuovere l'elemento in 'some directory'. Passo da remove-item a rm -r senza errori !?
Greg

Interessante. Ho degli strumenti Cygwin nella mia scatola, e ci ho provato rm -rf foldere ovviamente non ci sono riuscito. Inizialmente ho votato in giù la risposta (perché diceva Ubuntu). Grazie al commento di @chwarr, l'ho provato senza il fe ha raccolto l'alias piuttosto che rm binary. Vorrei che Tuan aggiornasse la sua fonte (non sono sicuro che Tuan sapesse che era un alias o pensava davvero che fosse l'unix rm ;-)
Joshua Ball

2
Forse è perché uso -Rinvece di -r(anche se per quanto ne so PowerShell è come il resto di Windows senza distinzione tra maiuscole e minuscole, quindi non dovrebbe fare la differenza) ma ho avuto un errore che le cartelle che sto cercando di eliminare sono non vuoto.
rbaleksandar,

25

Quando si eliminano i file in modo ricorsivo usando un semplice, a Remove-Item "folder" -Recursevolte vedo un errore intermittente:[folder] cannot be removed because it is not empty.

Questa risposta tenta di prevenire tale errore eliminando singolarmente i file.

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 dettaglio importante è l'ordinamento di tutti gli elementi in pspath -Descendingmodo che le foglie vengano eliminate prima delle radici. L'ordinamento viene eseguito sul pspathparametro poiché ha maggiori possibilità di lavorare per provider diversi dal file system. Il -Includeparametro è solo una comodità se si desidera filtrare gli elementi da eliminare.

È diviso in due funzioni poiché trovo utile vedere cosa sto per eliminare eseguendo

Get-Tree some_dir | select fullname

1
Durante la risoluzione di un problema utilizzando PowerShell negli script di build di TFS, questa si è rivelata la risposta corretta.
rcabr,

Questa è la soluzione anche per me. Concediti dei punti, amico mio!
Jammer,

Ha funzionato per me. Non ho potuto ottenere la cancellazione ricorsiva dei contenuti di una cartella, ma la tua soluzione ha funzionato per me. grazie
SheldonH

Questa è una soluzione molto robusta
Max Young,

Non sono sicuro del motivo per cui la risposta accettata abbia così tanti voti - Personalmente ricevo ancora errori intermittenti utilizzando remove-item -recursePowershell v5, quindi questa soluzione è la migliore per me.
JonoB,


11

Prova questo esempio. Se la directory non esiste, non viene generato alcun errore. Potrebbe essere necessario PowerShell v3.0.

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

7

Utilizzare il comando DOS old-school:

rd /s <dir>

Se questo fa parte di uno script, dovresti usare /q(Modalità silenziosa, non chiedere se ok per rimuovere anche un albero di directory con / S).
wildeyes,

6

Per qualche ragione la risposta di John Rees a volte non ha funzionato nel mio caso. Ma mi ha portato nella seguente direzione. Per prima cosa provo a eliminare la directory in modo ricorsivo con l'opzione buggy -recurse. Successivamente scendo in ogni sottodiretto rimasto ed elimino tutti i file.

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
        }
    }
}

Riesci a riprodurre l'errore quando eseguo le mie funzioni? Mi piacerebbe saperlo per poterli migliorare.
John Rees,

Spiacenti, non ricordare l'impostazione esatta. : / Penso che sia stato quando sono state coinvolte più sottodirectory. È successo che la chiamata a "Remove-Item -force -recurse" non ha eliminato tutti i file e in quel caso l'ultimo Remove-Tree non è riuscito perché la directory non era vuota. Ecco perché mi è venuta in mente la nuova soluzione per provare prima la versione integrata buggy (-force) e poi scendere manualmente in ciascuna directory ed eliminare "manualmente" ciò che resta. Questa versione è in uso regolarmente e fino ad ora funziona. L'unica causa che ha fallito è stata quando un programma ha ancora un handle in una directory.
jdoose,

5

Per evitare gli errori "La directory non è vuota" della risposta accettata, basta usare il buon vecchio comando DOS come suggerito prima. La sintassi completa di PS pronta per il copia-incolla è:

& cmd.exe /c rd /S /Q $folderToDelete

3
Dà ancora l'errore "La directory non è vuota" per le cartelle !?
Oncel Umut TURER,

2

Ho preso un altro approccio ispirato da @ john-rees sopra - specialmente quando il suo approccio ha iniziato a fallire per me ad un certo punto. Fondamentalmente ricorre alla sottostruttura e ordina i file in base alla loro lunghezza del percorso - elimina dal più lungo al più 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

Per quanto riguarda la magia -LiteralPath, ecco un altro gotchya che potrebbe colpire te: https://superuser.com/q/212808


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

O

remove-item <dir> -Recurse -Force

Se hai una directory enorme, quello che faccio di solito è

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

Eseguilo su un altro terminale PowerShell e si fermerà al termine.


Ammetto che la tua idea con il monitoraggio può essere utile, ma è appena diversa dalla semplice stampa di un messaggio una volta terminata, e nel caso in cui si sia verificato un problema durante l'interruzione di Rimuovi-elemento, il ciclo non finirà mai.
Raúl Salinas-Monteagudo,

@ RaúlSalinas-Monteagudo vero, ma è sicuramente per lo scenario di caso d'uso incustodito o prod. Deve essere abbastanza piccolo da consentire a qualcuno di ricordare e digitare in movimento e di non eseguire un sofisticato file .ps1 in una sola directory.
Gajendra D Ambi

2

L'eliminazione di un intero albero delle cartelle a volte funziona e talvolta non riesce con errori "Directory non vuota". Il tentativo successivo di verificare se la cartella esiste ancora può causare errori "Accesso negato" o "Accesso non autorizzato". Non so perché questo accada, anche se alcuni approfondimenti possono essere acquisiti da questa pubblicazione StackOverflow .

Sono stato in grado di aggirare questi problemi specificando l'ordine in cui gli elementi all'interno della cartella vengono eliminati e aggiungendo ritardi. Quanto segue funziona bene per me:

# 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 articolo di Microsoft TechNet sull'utilizzo delle proprietà calcolate in PowerShell mi è stato utile per ottenere un elenco di sottocartelle ordinate per profondità.

Problemi di affidabilità simili con RD / S / Q possono essere risolti eseguendo DEL / F / S / Q prima RD / S / Q e l'esecuzione del RD una seconda volta se necessario - idealmente con una pausa tra (vale a dire utilizzando ping come mostrato sotto).

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

1

Davvero semplice:

remove-item -path <type in file or directory name>, press Enter

Dovresti offrire anche un'esempio di esecuzione.
indivisibile

1

Un altro trucco utile:

Se trovi molti file con convenzione di nome uguale o simile (come file mac con nome prefisso punto ... quel famoso pull di file), puoi rimuoverli facilmente con una sola riga dalla PowerShell in questo modo:

ls -r .* | rm

Questa riga rimuoverà tutti i file con un punto all'inizio del nome all'interno della directory corrente e anche tutti i file con le stesse circostanze all'interno di altre cartelle all'interno di questa directory. Siate consapevoli durante l'utilizzo. : D


Perché non usare rm -rf .*? Non ho PowerShell da testare, ma penso che funzionerà.
Vini.g.fer

1
È facile; se si rimuove semplicemente "| rm" dal comando, è possibile visualizzare un intero panorama di ciò che si intende eliminare, dopo averne la certezza, è possibile completare il comando.
Daniel Alberto Lepe Ayala,

Di certo, per quitar los archivos que empiecen con punto, (come los de mac) per tutto il mondo propiedad de oculto, quindi usar: ls -r -h. * | rm
Daniel Alberto Lepe Ayala

1

Per eliminare il contenuto completo inclusa la struttura delle cartelle, utilizzare

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

L' -recurseaggiunta per remove-itemgarantire che i prompt interattivi siano disabilitati.


-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"
}

Scritto quanto sopra per pulire alcuni file di registro senza eliminare la directory principale e questo funziona perfettamente!


-2
rm -r <folder_name>
c:\>rm -r "my photos"

1
Per favore, spiegalo in modo tale che altri possano imparare dalla tua risposta
Nico Haase,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.