Как рекурсивно удалить весь каталог с помощью 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
PowerShell, я знаю, ноRD /S /Q
— Рубенс Фариас


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

2
«RD / S / Q», похоже, не работает в PowerShell - говорит «Remove-Item: не найден позиционный параметр, который принимает аргумент« / q »».
— BrainSlugs83

5
rdэто псевдоним для Remove-ItemPowerShell. cmd /c "rd /s /q"работает, хотя.
— Codekaizen

Ответы:


511
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.
— Джои

2
@Joey «Кажется, что вызов delete возвращается раньше, чем файл или папка действительно удалены, что иногда вызывает проблемы». -> Для пояснения: родительская папка не будет удалена, и появляется следующая ошибка: «[родительская папка] не может быть удалена, поскольку она не пуста». Я вижу, что это происходит постоянно на (медленных) сетевых дисках. Единственное решение - старое: cmd /c rdкак указано ниже.
— Давор Йосипович

6
Что насчет ошибок "Каталог не пустой"? serverfault.com/questions/199921/powershell-remove-force Может быть лучше get-childitem * -include * .csv -recurse | удалить элемент я не знаю См stackoverflow.com/a/1668471/206730
— Kiquenet

39

Я использовал:

rm -r folderToDelete

Это работает для меня как шарм (я украл его из Ubuntu).


Разве для этого не требуется cygwin, git или какой-либо другой инструмент, который может имитировать оболочку bash в Windows?
— Пит

19
@ Пит, нет, для этого не требуется ничего, кроме 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» работает лучше, чем прямое использование remove-item. Я получил те же ошибки: «Невозможно удалить элемент в« некотором каталоге ». Я переключаюсь с remove-item на rm -r без ошибок !?»
— Greg

Интересный. У меня есть инструменты 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

Это решение для меня тоже. У меня есть некоторые моменты, мой хороший человек!
— Jammer

Работал на меня. Я не смог получить рекурсивное удаление содержимого папки, но ваше решение сработало для меня. спасибо
— SheldonH

Это очень надежное решение
— Макс Янг

Я не уверен, почему принятый ответ имеет так много голосов - лично я все еще получаю периодические ошибки при использовании remove-item -recurseв Powershell 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

Почему-то ответ Джона Риса иногда не работал в моем случае. Но это привело меня в следующем направлении. Сначала я пытаюсь рекурсивно удалить каталог с ошибкой -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-Tree не удался, потому что каталог не был пустым. Вот почему я придумал новое решение, чтобы сначала попробовать исправленную встроенную версию (-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}

Запустите это на другом терминале powershell, и он остановится, когда это будет сделано.


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

@ RaúlSalinas-Monteagudo верно, но это определенно для продвинутого или необслуживаемого сценария использования. Он должен быть достаточно маленьким, чтобы кто-то мог просто запомнить и напечатать на ходу, а не запускать сложный файл .ps1 в просто каталог.
— Гаджендра Д Амби

2

Удаление всего дерева папок иногда работает, а иногда приводит к ошибкам «Directory not empty». Впоследствии попытка проверить, существует ли папка, может привести к ошибкам «Доступ запрещен» или «Несанкционированный доступ». Я не знаю, почему это происходит, хотя некоторая информация может быть получена из этой публикации 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

Действительно просто:

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

Вы также должны предложить пример исполнения.
— неразделимо

1

Еще один полезный трюк:

Если вы найдете множество файлов с одинаковыми или похожими именами (например, mac-файл с префиксным именем точки ... с этим известным извлечением файла), вы можете легко удалить их одной строкой из powershell, например так:

ls -r .* | rm

Эта строка удалит все файлы с точкой в ​​начале имени внутри текущего каталога, а также все файлы с такими же обстоятельствами в других папках внутри этого каталога. Помните об этом при использовании. : D


Почему бы не использовать rm -rf .*? У меня нет PowerShell для тестирования, но я думаю, что это сработает.
— 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.