Jak rekurencyjnie usunąć cały katalog za pomocą PowerShell 2.0?


308

Jaki jest najprostszy sposób, aby wymusić usunięcie katalogu i wszystkich jego podkatalogów w PowerShell? Korzystam z programu PowerShell V2 w systemie Windows 7.

Nauczyłem się z kilku źródeł, że najbardziej oczywiste polecenie Remove-Item $targetDir -Recurse -Forcenie działa poprawnie. Obejmuje to oświadczenie w pomocy online programu PowerShell V2 (znalezione przy użyciu Get-Help Remove-Item -Examples), które stwierdza:

... Ponieważ parametr Recurse w tym poleceniu cmdlet jest wadliwy, polecenie używa polecenia cmdlet Get-Childitem, aby uzyskać pożądane pliki, i używa operatora potoku do przekazania ich do polecenia cmdlet Remove-Item ...

Widziałem różne przykłady, które używają Get-ChildItem i potokują go do Remove-Item , ale przykłady zwykle usuwają pewien zestaw plików oparty na filtrze, a nie cały katalog.

Szukam najczystszego sposobu wysadzenia całego katalogu, plików i katalogów podrzędnych, bez generowania komunikatów ostrzegawczych użytkownika przy użyciu najmniejszej ilości kodu. Jednoliniowy byłby miły, jeśli jest łatwy do zrozumienia.


2
PowerShell, wiem, aleRD /S /Q
Rubens Farias


Nie sądzę, że to duplikat. Przejrzałem 1667145 przed wysłaniem. Pyta, dlaczego PowerShell nie ustawia poprawnie parametru bool Recurse podczas wywoływania implementacji metody Remove-Item niestandardowego dostawcy PowerShell. Pytałem o zachowanie Usuń element, ponieważ dotyczy ono wbudowanego dostawcy systemu plików.
Matt Spradley,

2
„RD / S / Q” nie działa w PowerShell - mówi „Usuń element: Nie można znaleźć parametru pozycyjnego, który akceptuje argument„ / q ”.”
BrainSlugs83

5
rdto alias dla Remove-Itemw PowerShell. cmd /c "rd /s /q"działa jednak.
codekaizen

Odpowiedzi:


510
Remove-Item -Recurse -Force some_dir

rzeczywiście działa zgodnie z reklamą tutaj.

rm -r -fo some_dir

są skrótami, które też działają.

O ile rozumiem, -Recurse parametr po prostu nie działa poprawnie, gdy próbujesz rekurencyjnie usunąć przefiltrowany zestaw plików. Wydaje się, że zabicie jednego katalogu i wszystkiego poniżej działa dobrze.


5
Myślę że masz rację. Otrzymałem komunikat „Nie można usunąć elementu z„ jakiegoś katalogu ”, ponieważ jest w użyciu.” błąd i założył, że jest to problem z algorytmem rekurencyjnym, i poszedłem poszukać obejścia. Okazuje się, że wcześniej uruchomiłem proces w skrypcie, który działał w katalogu docelowym. Po zmianie skryptu w celu oczekiwania na drugi proces działa polecenie „Usuń-element-Odzyskaj-Wymuś”. Zawsze najpierw spójrz w lustro :)
Matt Spradley,

15
Przekonałem się, że muszę to uruchomić dwa razy, gdy uruchamiam katalog zawierający podkatalogi. Za pierwszym razem pojawi się wiele błędów „Katalog nie jest pusty”. Za drugim razem kończy się bez błędów.
Kristopher Johnson

5
Kristopher Johnson, dostaję podobne błędy z różnymi narzędziami w systemie Windows 7. Wygląda na to, że wywołanie usuwania powraca wcześniej niż plik lub folder jest faktycznie usuwany, co czasami powoduje problemy. Wydaje się, że dzieje się tak w Explorer, Far, cmd i PowerShell.
Joey,

2
@Joey „Wygląda na to, że wywołanie usuwania powraca wcześniej niż plik lub folder jest faktycznie usuwany, co czasami powoduje problemy”. -> Dla wyjaśnienia: folder nadrzędny nie zostanie usunięty i pojawi się następujący błąd: „Nie można usunąć [folderu nadrzędnego], ponieważ nie jest pusty”. Widzę, że dzieje się to stale na (wolnych) dyskach sieciowych. Jedynym rozwiązaniem jest stare: cmd /c rdjak podano poniżej.
Davor Josipovic,

6
Co z błędami „Katalog nie jest pusty”? serverfault.com/questions/199921/powershell-remove-force Może lepiej get-childitem * -include * .csv -recurse | usuń element Nie wiem. Zobacz stackoverflow.com/a/1668471/206730
Kiquenet

39

Użyłem:

rm -r folderToDelete

Działa to dla mnie jak urok (ukradłem go z Ubuntu).


Czy to nie wymaga cygwina, gita lub innego narzędzia, które może symulować powłokę bash w systemie Windows?
Pete,

19
@Pete, nie, nie wymaga niczego oprócz PowerShell. rmto alias dla Remove-Itemdomyślnej konfiguracji PowerShell. Sprawdź wyniki, Get-Alias rmaby uzyskać więcej informacji. -rSię korzystając z częściowym zachowaniem dopasowania PowerShell w sprawie parametrów. Ponieważ Remove-Itemma tylko jeden parametr rozpoczynający się od „r” -Recurse, -rpasuje do tego. Tak więc, po wszystko będzie działać tak samo: rm -r, rm -re, Remove-Item -Recurse. (Uwaga: ani rm -rfani nie rm -r -fbędzie działać, ale rm -r -fobędzie. Nie -rfpasuje do żadnych parametrów i -fpasuje do więcej niż jednego.)
chwarr

1
Co ty na to. Alias ​​rm Powershell dla „Remove-Item -Recurse -Force some_dir” działa lepiej niż bezpośrednio przy użyciu remove-item. Otrzymałem te same błędy „Nie można usunąć elementu z„ jakiegoś katalogu ”. Przełączam się z remove-item na rm -r bez błędów !?
Greg

Ciekawy. Mam na swoim komputerze narzędzia cygwin i próbowałem rm -rf folderi oczywiście nie udało się. Początkowo głosowałem za odpowiedzią (ponieważ napisano Ubuntu). Dzięki komentarzowi @chwarr, wypróbowałem go bez niego fi wybrałem alias zamiast binarnego rm. Chciałbym, żeby Tuan zaktualizował swoje źródło (nie jestem pewien, czy Tuan wiedział, że to był pseudonim, czy naprawdę myślał, że to unix rm ;-)
Joshua Ball

2
Być może dzieje się tak dlatego, że używam -Rzamiast -r(choć o ile wiem, PowerShell jest podobny do reszty systemu Windows, bez rozróżniania wielkości liter, dlatego nie powinno to robić różnicy), ale mam błąd, że foldery, które próbuję usunąć, są nie pusty.
rbaleksandar

25

Podczas usuwania plików rekurencyjnie za pomocą prostego Remove-Item "folder" -Recurseczasami widzę przejściowy błąd:[folder] cannot be removed because it is not empty.

Ta odpowiedź próbuje zapobiec temu błędowi poprzez indywidualne usunięcie plików.

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

Ważnym szczegółem jest sortowanie wszystkich elementów za pomocą, pspath -Descendingaby liście były usuwane przed korzeniami. Sortowanie odbywa się na podstawie pspathparametru, ponieważ ma to większą szansę na pracę dla dostawców innych niż system plików. The-Include parametr jest tylko wygodą, jeśli chcesz filtrować elementy do usunięcia.

Jest podzielony na dwie funkcje, ponieważ uważam, że przydatne jest sprawdzenie, co zamierzam usunąć, uruchamiając

Get-Tree some_dir | select fullname

1
Rozwiązanie problemu przy użyciu programu PowerShell w skryptach kompilacji TFS okazało się poprawną odpowiedzią.
rcabr

To jest również rozwiązanie dla mnie. Zdobądź kilka punktów, mój dobry człowieku!
Jammer

Pracował dla mnie. Nie mogłem uzyskać rekurencyjnego usunięcia zawartości folderu, ale twoje rozwiązanie zadziałało dla mnie. dzięki
SheldonH 26.04.16

To bardzo solidne rozwiązanie
Max Young,

Nie jestem pewien, dlaczego zaakceptowana odpowiedź ma tak wiele głosów - osobiście wciąż dostaję sporadyczne błędy przy użyciu remove-item -recursePowershell v5, więc to rozwiązanie jest dla mnie najlepsze.
JonoB,


11

Wypróbuj ten przykład. Jeśli katalog nie istnieje, nie pojawia się błąd. Możesz potrzebować PowerShell v3.0.

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

7

Użyj old-schoolowej komendy DOS:

rd /s <dir>

Jeśli jest to część skryptu, musisz użyć /q(Tryb cichy, nie pytaj, czy możesz usunąć drzewo katalogów za pomocą / S).
wildeyes

6

Z jakiegoś powodu odpowiedź Johna Reesa czasami nie działała w moim przypadku. Ale poprowadziło mnie to w następującym kierunku. Najpierw próbuję usunąć katalog rekurencyjnie za pomocą opcji buggy -recurse. Następnie schodzę do każdego pozostałego podkatalogu i usuwam wszystkie pliki.

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

Czy możesz odtworzyć błąd podczas uruchamiania moich funkcji? Chciałbym wiedzieć, żebym mógł je ulepszyć.
John Rees,

Przepraszamy, nie pamiętam dokładnego ustawienia. : / Myślę, że było tak, gdy zaangażowanych było wiele podkatalogów. Zdarzyło się, że wywołanie „Remove-Item-force -recurse” nie usunęło wszystkich plików, w tym przypadku ostatnie usunięcie drzewa nie powiodło się, ponieważ katalog nie był pusty. Właśnie dlatego wymyśliłem nowe rozwiązanie, aby najpierw wypróbować wbudowaną wersję buggy (-force), a następnie ręcznie zejść do każdego katalogu i usunąć „ręcznie” to, co zostało. Ta wersja jest używana regularnie i do tej pory działa. Jedyną przyczyną niepowodzenia było to, że program nadal ma uchwyt katalogu.
jdoose

5

Aby uniknąć błędów „Katalog nie jest pusty” w zaakceptowanej odpowiedzi, po prostu użyj starej, dobrej komendy DOS, jak sugerowano wcześniej. Pełna składnia PS gotowa do wklejania kopii to:

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

3
Nadal pojawia się błąd „Katalog nie jest pusty” dla folderów !?
Oncel Umut TURER

2

Przyjąłem inne podejście zainspirowane przez @ john-rees powyżej - szczególnie, gdy jego podejście zaczęło mi się nie udać w pewnym momencie. Zasadniczo powtórz poddrzewo i posortuj pliki według ich długości ścieżki - usuń od najdłuższego do najkrótszego

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

Jeśli chodzi o magię -LiteralPath, oto kolejna gotchya, która może cię uderzyć: https://superuser.com/q/212808


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

LUB

remove-item <dir> -Recurse -Force

Jeśli masz ogromny katalog, zazwyczaj robię to

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

Uruchom to na innym terminalu PowerShell, a zatrzyma się po zakończeniu.


Przyznaję, że twój pomysł z monitorowaniem może być przydatny, ale nie różni się niczym od wydrukowania wiadomości po jej zakończeniu, a na wypadek, gdyby wystąpił problem z zatrzymaniem elementu usuwania, twoja pętla nigdy się nie skończy.
Raúl Salinas-Monteagudo

@ RaúlSalinas-Monteagudo prawda, ale zdecydowanie jest to przypadek prod lub nienadzorowany przypadek użycia. Musi być wystarczająco mały, aby ktoś mógł zapamiętać i pisać w ruchu, a nie uruchamiać wyrafinowanego pliku .ps1 tylko w katalogu.
Gajendra D Ambi

2

Usunięcie całego drzewa folderów czasami działa, a czasami kończy się niepowodzeniem z błędami „Katalog nie jest pusty”. Późniejsza próba sprawdzenia, czy folder nadal istnieje, może spowodować błędy „Odmowa dostępu” lub „Nieautoryzowany dostęp”. Nie wiem, dlaczego tak się dzieje, choć można uzyskać wgląd w ten post StackOverflow .

Udało mi się obejść te problemy, określając kolejność usuwania elementów w folderze i dodając opóźnienia. Dla mnie dobrze działa:

# 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

Artykuł Microsoft TechNet Korzystanie z właściwości obliczeniowych w programie PowerShell pomógł mi w uzyskaniu listy podfolderów posortowanych według głębokości.

Podobne problemy z niezawodnością z RD / S / Q można rozwiązać, uruchamiając DEL / F / S / Q przed RD / S / Q i uruchamiając RD po raz drugi, jeśli to konieczne - najlepiej z przerwą pomiędzy nimi (tj. Używając pingowania jak pokazano poniżej).

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

Naprawdę proste:

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

Powinieneś także zaoferować przykładowe wykonanie.
niepodzielny

1

Kolejna przydatna sztuczka:

Jeśli znajdziesz wiele plików o tej samej lub podobnej konwencji nazw (np. Plik mac z nazwą prefiksu kropki ... to słynne wyciągnięcie pliku), możesz łatwo usunąć je za pomocą jednego wiersza z PowerShell w następujący sposób:

ls -r .* | rm

Ta linia usunie wszystkie pliki z kropką na początku nazwy w bieżącym katalogu, a także wszystkie pliki o takich samych okolicznościach w innych folderach w tym katalogu. Pamiętaj o tym podczas korzystania z niego. :RE


Dlaczego nie użyć rm -rf .*? Nie mam PowerShell do przetestowania, ale myślę, że to zadziała.
Vini.g.fer

1
To jest łatwe; jeśli po prostu usuniesz „| rm” z polecenia, możesz wyświetlić całą panoramę tego, co chcesz usunąć, po upewnieniu się, możesz wykonać polecenie.
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

Aby usunąć całą zawartość, w tym strukturę folderów, użyj

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

-recurseDodany do remove-item, zapewnia interaktywne komunikaty są wyłączone.


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

Napisałem powyższe, aby wyczyścić niektóre pliki dziennika bez usuwania katalogu nadrzędnego, a to działa idealnie!


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.