Як рекурсивно видалити весь каталог із 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.