Вопрос: Силовое удаление файлов и каталогов в PowerShell иногда происходит, но не всегда


Я пытаюсь удалить рекурсивно каталог с помощью rm -Force -Recurse somedirectory, Я получаю несколько ошибок «Directory not empty». Если я повторить ту же команду, он преуспевает.

Пример:

PS I:\Documents and Settings\m\My Documents\prg\net> rm -Force -Recurse .\FileHelpers
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests\Data\RunTime\_svn: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (_svn:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests\Data\RunTime: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (RunTime:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests\Data: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (Data:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\FileHelpers.Tests: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (FileHelpers.Tests:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\Libs\nunit\_svn: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (_svn:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\Libs\nunit: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (nunit:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers\Libs: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (Libs:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Remove-Item : Cannot remove item I:\Documents and Settings\m\My Documents\prg\net\FileHelpers: The directory is not empty.
At line:1 char:3
+ rm <<<<  -Force -Recurse .\FileHelpers
    + CategoryInfo          : WriteError: (I:\Documents an...net\FileHelpers:DirectoryInfo) [Remove-Item], IOException
    + FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS I:\Documents and Settings\m\My Documents\prg\net> rm -Force -Recurse .\FileHelpers
PS I:\Documents and Settings\m\My Documents\prg\net>

Конечно, этого не происходит всегда, Кроме того, это происходит не только с _svn каталогов, и у меня нет TortoiseSVN кеш или что-то в этом роде, поэтому ничто не блокирует каталог.

Есть идеи?


25
2017-11-09 15:42


Источник




Ответы:


help Remove-Item говорит:

Параметр Recurse в этом командлете не работает должным образом.

а также

Поскольку параметр Recurse в этом командлете неисправен, команда использует командлет Get-Childitem, чтобы получить желание   d, и использует оператор конвейера для передачи их командлету Remove-Item.

и предлагает эту альтернативу в качестве примера:

get-childitem * -include *.csv -recurse | remove-item

Так что вы должны трубить get-childitem -recurse в remove-item,


28
2017-11-09 18:35



Благодарю. Только что нашел эту тему с 2006 года: vistax64.com/powershell/... похоже, что Microsoft действительно не заинтересована в этом. - Mauricio Scheffer
@mausch: см. это более свежий, но все еще неразрешенный, ссылка: Удалить-Item -Recurse - Dennis Williamson
если вы совершаете обход и удаляете, сначала вам нужно пройти сначала дочерние каталоги и их файлы. - fschwiet
По крайней мере, в документации говорится, что он не работает. - derekerdmann
Мне пришлось поместить оба флага -force -recurse для Remove-Item, в противном случае он заставил меня запрашивать «пожалуйста, подтвердите» Get-ChildItem -Path $ Destination -Recurse | Удалить-Item -force -recurse - Michael Freidgeim


@JamesCW: проблема все еще существует в PowerShell 4.0

Я попробовал другое обходное решение, и это сработало: используйте cmd.exe:

&cmd.exe /c rd /s /q $somedirectory

10
2017-09-10 06:59



Хороший старый rd / s / q! - JamesCW
Я пробовал все варианты Get-ChildItem; петли повтора; призвание iisreset перед удалением и ничего не работает надежно, Я собираюсь попробовать этот, хотя, когда я впервые увидел его, я отказался от DOS внутри моей Powershell ... - Peter McEvoy


Новая версия PowerShell (PSVersion 4.0) полностью разрешил этот вопрос и Remove-Item "targetdirectory" -Recurse -Force работает без каких-либо проблем времени.

Вы можете проверить свою версию, запустив $PSVersiontable из ISE или PowerShell незамедлительный. 4.0 - это версия, которая поставляется с Windows 8.1 а также Server 2012 R2, и его можно установить и в предыдущих версиях Windows.


6
2018-05-27 15:36



Все еще происходит для меня в PowerShell 4.0 - ajbeaven
Все еще происходит в PowerShell v5 !!!!! 11 !! 1! 1 !!! - Richard Hauer
@RichardHauer хорошо, теперь я просто смущен - JamesCW
@JamesCW Я преобразовал в rd версия. Помимо фактически работающих, это примерно в 3 раза быстрее - Richard Hauer


Текущий ответ фактически не будет удалять каталог, а только его дочерние элементы. Кроме того, он будет иметь проблемы с вложенными каталогами, поскольку он снова попытается удалить каталог до его содержимого. Я написал что-то, чтобы удалить файлы в правильном порядке, все равно будет иметь ту же проблему, хотя иногда каталог все равно будет вокруг.

Итак, теперь я использую что-то, что поймает исключение, подождите и повторит попытку (3 раза):

Пока я использую это:

function EmptyDirectory($directory = $(throw "Required parameter missing")) {

    if ((test-path $directory) -and -not (gi $directory | ? { $_.PSIsContainer })) {
        throw ("EmptyDirectory called on non-directory.");
    }

    $finished = $false;
    $attemptsLeft = 3;

    do {
        if (test-path $directory) {
            rm $directory -recurse -force
        }

        try {
            $null = mkdir $directory
            $finished = $true
        } 
        catch [System.IO.IOException] {
            Start-Sleep -Milliseconds 500
        }

        $attemptsLeft = $attemptsLeft - 1;
    } 
    while (-not $finished -and $attemptsLeft -gt 0)

    if (-not $finished) {
        throw ("Unable to clean and recreate directory " + $directory)
    }
}

3
2017-12-26 22:36



Это хорошо, но у меня все еще были проблемы с этим. Если команда mkdir выполняется до того, как система завершит команду rm, она может выдать исключение System.UnauthorizedAccessException с помощью FullyQualifiedErrorId из ItemExistsUnauthorizedAccessError. I.e., каталог еще не был удален ОС (на моем медленном жестком диске). Так что ошибка должна быть поймана. И это необратимая ошибка, поэтому для ErrorAction необходимо установить значение Стоп. Я также помещаю команду rm в блок try, а также в случаях, когда при удалении происходят прерывистые ошибки ввода-вывода. - Mark Lapierre
Я не могу поверить, что это даже нужно сделать. Черт, Powershell сосет! - jcollum


Для удаления каталога и его содержимого требуется два шага. Сначала удалите содержимое, а затем папку. Используя обходной путь для ошибочного рекурсивного удаления элемента, решение будет выглядеть так:

Get-ChildItem -Path "$folder\\*" -Recurse | Remove-Item -Force -Recurse
Remove-Item $folder

Таким образом вы также можете удалить родительский каталог.


3
2017-12-13 23:40



Это именно то, что сказал принятый ответ. У вас есть что добавить? - Michael Hampton♦
Они указывают, что принятый ответ не удаляет сам каталог, поэтому он принимает два шага. - Paul George
Remove-Item команда вашего трубопровода в имеет ту же проблему, что изначально заявлено. Он может наткнуться на элемент каталога, который не является пустым таким же образом. - Dejan
@Dejan Этот каталог не может быть пустым, если первая строка этого кода работает, не так ли? - Ifedi Okonkwo


Это то, что я работаю:

$Target = "c:\folder_to_delete"

Get-ChildItem -Path $Target -Recurse -force |
  Where-Object { -not ($_.psiscontainer) } |
   Remove-Item –Force

Remove-Item -Recurse -Force $Target

Эта первая строка удаляет все файлы в дереве. Второй удаляет все папки, включая верхнюю.


2
2017-09-30 21:20





Сначала возьмитесь за файлы / каталоги, используя Takeown.exe, затем удалите

https://learn-powershell.net/2014/06/24/changing-ownership-of-file-or-folder-using-powershell/


0
2017-08-17 17:18