Як рекурсивно видалити весь каталог із PowerShell 2.0?


308

Який найпростіший спосіб насильно видалити каталог та всі його підкаталоги в PowerShell? Я використовую PowerShell V2 в Windows 7.

Я дізнався з кількох джерел, що найочевидніша команда Remove-Item $targetDir -Recurse -Force, працює не правильно. Сюди входить твердження в онлайн-довідці PowerShell V2 (знайдено за допомогою Get-Help Remove-Item -Examples), в якій зазначено:

... Оскільки параметр Recurse в цьому командлеті несправний, команда використовує командлет Get-Childitem для отримання потрібних файлів, і він використовує оператор конвеєра, щоб передати їх до командлету Remove-Item ...

Я бачив різні приклади, які використовують Get-ChildItem і передають його на Remove-Item , але з прикладів зазвичай видаляється якийсь набір файлів на основі фільтра, а не весь каталог.

Я шукаю найчистіший спосіб вивести весь каталог, файли та дочірні каталоги, не створюючи жодних попереджувальних повідомлень користувачів, використовуючи найменшу кількість коду. Однолінійне було б добре, якщо це легко зрозуміти.


2
powerhell, я знаю, алеRD /S /Q
— Рубенс Фаріас

можливий дублікат: stackoverflow.com/questions/1667145/…
— Rubens Farias

Я не думаю, що це дублікат. Я переглянув 1667145 перед публікацією. Це питання, чому PowerShell не встановлює належним чином параметр Recurse bool, коли викликає реалізацію методу Remove-Item спеціального постачальника PowerShell. Я запитував про поведінку Remove-Item, оскільки це стосується вбудованого постачальника файлових систем.
— Метт Спрадлі

2
"RD / S / Q", схоже, не працює в PowerShell - йдеться про "Remove-Item: не може бути встановлений позиційний параметр, який приймає аргумент '/ q'."
— BrainSlugs83

5
rdце псевдонім для Remove-Itemповноважень. cmd /c "rd /s /q"працює, хоча.
— codekaizen

Відповіді:


510
Remove-Item -Recurse -Force some_dir

дійсно працює, як рекламується тут.

rm -r -fo some_dir

- це короткометражні псевдоніми, які також працюють.

Наскільки я зрозумів, -Recurseпараметр просто не працює правильно, коли ви намагаєтесь рекурсивно видаляти відфільтрований набір файлів. За вбивство одного dir та все, що нижче, здається, працює добре.


5
Я думаю, ти прав. Я отримував "Неможливо видалити елемент у" деякому каталозі ", оскільки він використовується." Помилка та припускав, що це проблема з алгоритмом рекурсії та пішов на пошук вирішення. Виявляється, у мене був процес, який я звільнив раніше у сценарії, який працював у цільовому каталозі. При зміні скрипту чекати іншого процесу працює команда "Remove-Item -Recurse -Force". Завжди дивись у дзеркало спочатку :)
— Метт Спредлі

15
Я виявив, що мені потрібно запустити це двічі під час запуску в каталозі, що містить підкаталоги. Перший час буде багато помилок "Каталог не порожній". Вдруге він завершується без помилок.
— Крістофер Джонсон

5
Крістофер Джонсон, я отримую подібні помилки з різними інструментами в Windows 7. Схоже, що виклик видалення повертається раніше, ніж файл або папка насправді видаляється, викликаючи проблеми іноді. Це, здається, відбувається в Explorer, Far, cmd та PowerShell.
— Joey

2
@Joey "Схоже, що виклик видалення повертається раніше, ніж файл або папка насправді видалено, що іноді викликає проблеми." -> Для уточнення: батьківська папка не буде видалена, і вийде така помилка: "[батьківська папка] неможливо видалити, оскільки вона не порожня." Я бачу, що це відбувається постійно на (повільних) мережевих накопичувачах. Єдине рішення - це старе: cmd /c rdяк зазначено нижче.
— Давор Йосипович

6
Про помилки "Каталог не порожній"? serverfault.com/questions/199921/powershell-remove-force Можливо, краще get-childitem * -include * .csv -recurse | Remove-item я не знаю. Див stackoverflow.com/a/1668471/206730
— Kiquenet

39

Я використав:

rm -r folderToDelete

Це працює для мене як шарм (я вкрав його з Ubuntu).


Хіба для цього не потрібні cygwin, git чи якийсь інший інструмент, який може імітувати оболонку bash для Windows?
— Піт

19
@ Pete, ні, він не вимагає нічого, крім PowerShell. rmПсевдонім для Remove-Itemконфігурації за замовчуванням PowerShell. Перевірте вихід Get-Alias rmна більш детальну інформацію. Використання -rпереваг PowerShell щодо часткового узгодження параметрів. Оскільки Remove-Itemлише один параметр, який починається з 'r' -Recurse, -rвідповідає цьому. Таким чином, наступний все буде працювати так само: rm -r, rm -re, Remove-Item -Recurse. (Зауважте, що ні працює, rm -rfні rm -r -fбуде rm -r -fo. Не -rfвідповідає жодним параметрам і -fвідповідає більше, ніж одному.)
— chwarr

1
Як щодо цього. Псевдонім Powershell rm для "Remove-Item -Recurse -Force some_dir" працює краще, ніж безпосередньо використовуючи delete-item. Я отримав ті самі помилки "Не вдається вилучити елемент у" деякій каталозі ". Я переходжу з видалення-елемента на rm -r без помилок !?"
— Грег,

Цікаво. У мене в коробці є інструменти cygwin, і я намагався, rm -rf folderі, звичайно, не вдалося. Я спочатку вниз проголосував відповідь (тому що він сказав Ubuntu). Завдяки коментарю @chwarr, я спробував це без, fі він взяв псевдонім, а не rm бінарний. Я б хотів, щоб Туан оновлював своє джерело (не впевнений, чи знав Туан, що це псевдонім чи справді думав, що це unix rm ;-)
— Джошуа Бал

2
Можливо, це тому, що я використовую -Rзамість цього -r(хоча, наскільки я знаю, PowerShell схожий на решту Windows не відрізняється від регістру, тому це не повинно змінити), але я отримав помилку, що папки, які я намагаюся видалити, не порожній.
— rbaleksandar

25

При рекурсивному видаленні файлів за допомогою простого Remove-Item "folder" -Recurseінколи я бачу переривчасту помилку:[folder] cannot be removed because it is not empty.

Ця відповідь намагається запобігти цій помилці шляхом індивідуального видалення файлів.

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

Важливою деталлю є сортування всіх предметів, pspath -Descendingщоб листя видалялися перед корінням. Сортування проводиться за pspathпараметром, оскільки це має більше шансів працювати для інших постачальників, ніж файлова система. -IncludeПараметр тільки для зручності , якщо ви хочете , щоб відфільтрувати елементи для видалення.

Він розділений на дві функції, оскільки мені здається корисним побачити, що я збираюсь видалити, запустивши

Get-Tree some_dir | select fullname

1
Під час вирішення проблеми за допомогою PowerShell в сценаріях побудови TFS це виявилося правильною відповіддю.
— rcabr

Це рішення і для мене. Попросіть собі декілька балів мій добрий чоловік!
— Джаммер

Працювали для мене. Я не міг отримати рекурсивне видалення вмісту папки, але ваше рішення працювало на мене. спасибі
— SheldonH

Це дуже надійне рішення
— Макс Янг

Я не впевнений, чому прийнята відповідь має стільки голосів - я особисто все ще отримую переривчасті помилки, використовуючи remove-item -recursePowershell v5, тому це рішення найкраще для мене.
— JonoB


11

Спробуйте цей приклад. Якщо каталог не існує, помилка не виникає. Можливо, вам знадобиться PowerShell v3.0.

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

7

Використовуйте команду DOS старої школи:

rd /s <dir>

Якщо це частина сценарію, вам доведеться використовувати /q(Тихий режим, не запитуйте, чи гаразд видаляти дерево каталогів з / S).
— wildeyes

6

Чомусь відповідь Джона Різа іноді не працювала в моєму випадку. Але це вело мене в наступному напрямку. Спочатку я намагаюся видалити каталог рекурсивно за допомогою параметра buggy -recurse. Після цього я спускаюсь до кожного піддіректа, що залишився, і видаляю всі файли.

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

Чи можете ви відтворити помилку під час виконання моїх функцій? Мені хотілося б знати, щоб я міг їх покращити.
— Джон Рис

Вибачте, не пам’ятайте точного налаштування. : / Я думаю, це було, коли було залучено кілька підкаталогів. Було так, що виклик "Remove-Item -force -recurse" не видалив усі файли, і в цьому випадку останнє дерево Remove-дерева не вдалося, оскільки каталог не був порожнім. Ось чому я придумав нове рішення спершу спробувати вбудовану версію баггі (-force), а потім вручну спуститися в кожен каталог і видалити "вручну" те, що залишилося. Ця версія використовується регулярно і до цього часу вона працює. Єдиною причиною цього не вдалося, коли програма все ще містить ручку до каталогу.
— jdoose

5

Щоб уникнути помилок "Каталог не порожній" прийнятої відповіді, просто використовуйте стару добру команду DOS, як було запропоновано раніше. Повний синтаксис PS, готовий до вставлення копій, це:

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

3
Він все ще видає помилку "Каталог не порожній" для папок !?
— Oncel Umut TURER

2

Я взяв інший підхід, натхненний @ john-rees вище - особливо коли його підхід у якийсь момент почав провалюватися для мене. В основному рекурсуйте піддерево і сортуйте файли за їх довжиною - видаляйте від найдовшого до найкоротшого

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

Що стосується магії -LiteralPath, ось ще одна хетча, яка може вразити вас: https://superuser.com/q/212808


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

АБО

remove-item <dir> -Recurse -Force

Якщо у вас є величезний каталог, то я зазвичай роблю це

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

Запустіть це на іншому терміналі powerhell, і воно зупиниться, коли це буде зроблено.


Я визнаю, що ваша ідея з моніторингом може бути корисною, але вона ледве відрізняється від того, щоб просто надрукувати повідомлення, як тільки воно закінчиться, і якщо виникла проблема з зупинкою Remove-Item, ваш цикл ніколи не закінчиться.
— Рауль Салінас-Монтеагудо

@ RaúlSalinas-Monteagudo правда, але це, безумовно, для вигідного або без нагляду сценарію використання. Він повинен бути досить малим, щоб хтось просто пам'ятав і вводив на ходу, а не запускав складний .ps1-файл лише до каталогу.
— Гаджендра Д Амбі

2

Видалення цілого дерева папок іноді працює, а іноді не вдається з помилками "Каталог не порожній". Згодом спроба перевірити, чи папка все ще існує, може призвести до помилок "Заборонено доступ" або "Несанкціонований доступ". Я не знаю, чому це відбувається, хоча деяке розуміння можна отримати від цієї публікації в StackOverflow .

Мені вдалося обійти ці проблеми, вказавши порядок видалення елементів у папці та додавши затримки. Наступне добре працює для мене:

# 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

Стаття Microsoft TechNet Використання обчислених властивостей у PowerShell була мені корисною для отримання списку підпапок, відсортованих за глибиною.

Подібні проблеми надійності з RD / S / Q можна вирішити, запустивши DEL / F / S / Q перед RD / S / Q та запустивши RD вдруге, якщо це необхідно - в ідеалі з паузою між ними (тобто використовуючи ping, як показано нижче).

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

Ще одна корисна хитрість:

Якщо ви знайдете безліч файлів з однаковою або подібною умовою імені (наприклад, mac-файл з точкою префікса імені ... того знаменитого витягання файлу), ви можете легко видалити їх одним рядком із панелі повноважень, як це:

ls -r .* | rm

Цей рядок буде видаляти всі файли з крапкою на початку імені всередині поточного каталогу, і всі файли з однаковими обставинами в інших папках всередині цього каталогу. Будьте в курсі про це, використовуючи його. : D


Чому б не використовувати rm -rf .*? У мене немає повноважень для тестування, але я думаю, що це спрацює.
— Vini.g.fer

1
Це легко; якщо ви просто видалите команду "| rm" з команди, ви зможете переглянути цілу панораму того, що ви збираєтесь видалити, після того, як ви впевнені, ви можете виконати команду.
— Даніель Альберто Лепе Аяла

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
— Даніель Альберто Лепе Аяла

1

Щоб видалити повний вміст, включаючи структуру папок

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

-recurseДоданий в remove-itemзабезпечує проведення відключені інтерактивні підказки.


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

Написав вище, щоб очистити деякі логіни, не видаляючи батьківський каталог, і це прекрасно працює!


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

1
Будь ласка, поясніть, що далі таке, що інші можуть дізнатися з вашої відповіді
— Ніко Хааз,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.