Как рекурсивно удалить весь каталог с помощью 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
Рубенс Фариас
возможный дубликат: stackoverflow.com/questions/1667145/…
Рубенс Фариас
Я не думаю, что это дубликат. Я просмотрел 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
13
rm -r ./folder -Force    

... работал на меня

stevethecollier
источник
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
        }
    }
}
jdoose
источник
Можете ли вы воспроизвести ошибку при запуске моих функций? Я хотел бы знать, чтобы я мог улучшить их.
Джон Рис
Извините, не помню точную настройку. : / Я думаю, что это было, когда несколько подкаталогов, где участвуют. Случилось так, что вызов «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
MikeOnline
источник
1

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

remove-item -path <type in file or directory name>, press Enter
DusanV
источник
Вы также должны предложить пример исполнения.
неразделимо
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"
user3008
источник
1
Пожалуйста, объясните, что дальше так, чтобы другие могли учиться на вашем ответе
Нико Хаас