PowerShell의 파일 및 디렉토리 강제 제거가 때때로 실패하지만 항상 그런 것은 아닙니다.


33

과 함께 디렉토리를 반복적으로 삭제하려고하는데 rm -Force -Recurse somedirectory여러 개의 "디렉토리가 비어 있지 않습니다"오류가 발생합니다. 내가 경우 동일한 명령을 다시 시도 , 그것은 성공합니다.

예:

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 캐시 또는 이와 유사한 것이 없으므로 디렉토리를 차단하는 것이 없습니다.

어떤 아이디어?

답변:


31

help Remove-Item 말한다 :

이 cmdlet의 Recurse 매개 변수가 제대로 작동하지 않습니다.

이 cmdlet의 Recurse 매개 변수에 결함이 있으므로 명령은 Get-Childitem cmdlet을 사용하여 원하는 d 파일을 가져오고 파이프 라인 연산자를 사용하여 해당 파일을 Remove-Item cmdlet에 전달합니다.

이 대안을 예로 제안합니다.

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

당신이 파이프를해야 그래서 get-childitem -recurse속으로 remove-item.


감사. vistax64.com/powershell/… 2006 년 부터이 스레드를 찾았습니다. Microsoft가 실제로이 문제를 수정하는 데 관심이없는 것 같습니다.
Mauricio Scheffer 2

@mausch :보다 최근에 확인되었지만 여전히 해결되지 않은 참조를 참조하십시오. Remove-Item -Recurse
추가 통지가있을 때까지 일시 중지되었습니다.

순회 및 삭제를 수행하는 경우 하위 디렉토리를 먼저 순회하고 파일을 먼저 순회해야합니다.
fschwiet

2
적어도 문서에는 작동하지 않는다고 나와 있습니다.
derekerdmann

6
Remove-Item에 대해 -force -recurse 플래그를 모두 넣어야했습니다. 그렇지 않으면 "확인하십시오"라는 메시지가 계속 나타납니다. Get-ChildItem -Path $ Destination -Recurse | Remove-Item -force -recurse
MiFreidgeim SO 중지 그만

17

@JamesCW : 문제는 여전히 PowerShell 4.0에 있습니다.

다른 해결 방법을 시도하고 작동했습니다 .cmd.exe를 사용하십시오.

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

1
좋은 rd / s / q!
JamesCW

Get-ChildItem의 모든 변형을 시도했습니다. 재시도 루프; 호출 iisreset삭제하지 아무것도하기 전에하는 것은 작동하는 것 같다 안정적 . 처음 보았을 때 Powershell 내부에 DOS를 설치하는 데 어려움을 겪었지만이 방법을 시도 할 것입니다.
Peter McEvoy

불행하게도, rd /s(비록 겉으로는 적게 비해 너무 간헐적으로 실패 Remove-Item) : github.com/Microsoft/console/issues/309
mklement

그것은 나를 위해 c에 의한 슬래시를 좋아하지 않습니다. powershell -command와 cmd.exe 부분을 작은 따옴표로 묶어야합니까? " '/'연산자 다음에 값 표현식을 제공해야합니다." "표현식이나 진술에서 예상치 못한 토큰 'c'. 앞의 powershell 명령과 동일합니다. / 탈출해야합니까?
Michele

7

ETA 20181217 : PSVersion 4.0 이상은 일부 상황에서 여전히 실패합니다. Mehrdad Mirreza의 대체 답변 참조 및 mklement가 제출 한 버그 보고서

버그가 공식 수정을 기다리고 있기 때문에 mklement 는이 SO 답변 에서 개념 증명 솔루션을 제공합니다.

PowerShell( PSVersion 4.0) 의 새 버전은 이 문제를 완전히 해결했으며 Remove-Item "targetdirectory" -Recurse -Force타이밍 문제없이 작동합니다.

$PSVersiontableISE 또는 PowerShell프롬프트 내에서 실행하여 버전을 확인할 수 있습니다 . 4.0 버전이 함께 제공 Windows 8.1하고 Server 2012 R2, 그리고 그것은뿐만 아니라 이전 버전의 Windows에 설치할 수 있습니다.


5
PowerShell 4.0에서도 여전히 발생
ajbeaven

10
PowerShell v5에서도 여전히 발생합니다 !!!!! 11 !! 1! 1 !!!
Richard Hauer

@RichardHauer 잘 지금은 혼란스러워
JamesCW

2
@JamesCW rd버전으로 변환했습니다 . 을 제외하고 실제로 작동, 더 빨리 배에 관하여
리처드 하우어

Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1부터이 문제가 해결 되지 않았습니다 . 이 버그 보고서를 참조하십시오 . rd /s자주 실패 하지는 않지만 고장이 발생 합니다. 이 버그 보고서를 참조하십시오 .
mklement

4

업데이트 : Windows 파일 시스템 항목 제거 API를 동기식으로 만들 계획 이 있지만 Windows 10 버전 1903부터 아직 동기식이 아닙니다 . GitHub에 대한 이 의견을 참조하십시오 .


기존 답변 은 문제를 완화 하여 문제가 덜 발생하지만 근본 원인을 해결하지 못하므로 오류가 계속 발생할 수 있습니다.

Remove-Item -Recurse파일 및 디렉토리 제거를위한 Windows API 메소드는 본질적으로 비동기식 이며이를 설명 Remove-Item하지 않기 때문에 예기치 않게 비동기식 입니다.

이것은 간헐적으로 예측할 수없는 두 가지 방법 중 하나로 나타납니다.

  • 귀하의 경우 : 상위 디렉토리를 제거하려고 시도 할 때까지 하위 디렉토리 또는 파일의 디렉토리 제거가 아직 완료되지 않은 경우 비어 있지 않은 디렉토리 자체를 제거하지 못할 수 있습니다.

  • 덜 일반적 : 재 작성을 시도 할 때까지 제거가 아직 완료되지 않았기 때문에 제거 직후에 제거 된 디렉토리를 다시 작성하는 데 실패 할 수 있습니다.

문제는 PowerShell에서의 영향을하지 Remove-Item뿐만 아니라 cmd.exe이야 ' rd /s.NET의뿐만 아니라[System.IO.Directory]::Delete() :

/ PowerShell을 핵심 6.2.0-preview.1 /의 Windows PowerShell 버전 5.1의로 cmd.exe10.0.17134.407 / .NET 프레임 워크 4.7.03056, .NET 코어 2.1 Remove-Item,도 rd /s,도 [System.IO.Directory]::Delete()안정적으로 작동 그들이 있기 때문에, 비동기에 대한 계정에 실패 Windows API 파일 / 디렉토리 제거 기능의 동작 :

안정적인 동기 해결 방법 을 제공 하는 사용자 지정 PowerShell 기능 에 대해서는 이 SO 답변을 참조하십시오 .


제거가 확실한 파일을 처리 할 때 :while($true) { if ( (Remove-Item [...] *>&1) -ne $null) { Start-Sleep 0.5 } else { break } }
Farway

3

현재 답변은 실제로 디렉토리를 삭제하지 않으며 하위 디렉토리 만 삭제합니다. 또한 내용보다 먼저 디렉토리를 삭제하려고 시도하므로 중첩 디렉토리에 문제가 있습니다. 올바른 순서로 파일을 삭제하기 위해 무언가를 썼지 만 때로는 디렉토리가 여전히 뒤에있을지라도 여전히 같은 문제가 있습니다.

이제 예외를 포착하고 기다렸다가 다시 시도하는 것을 사용합니다 (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)
    }
}

1
이것은 좋지만 여전히 문제가 있습니다. 시스템이 rm 명령을 완료하기 전에 mkdir 명령이 실행되면 ItemExistsUnauthorizedAccessError의 FullyQualifiedErrorId와 함께 System.UnauthorizedAccessException이 발생할 수 있습니다. 즉, 디렉토리가 아직 느린 HDD에서 OS에 의해 삭제되지 않았습니다. 따라서 오류도 잡아야합니다. 그리고 종료되지 않은 오류이므로 ErrorAction을 Stop으로 설정해야합니다. 삭제시 일시적인 IO 오류가있는 경우를 대비하여 rm 명령을 try 블록에도 넣습니다.
Mark Lapierre

나는 이것이 완료되어야한다고 믿을 수 없다. 젠장, Powershell이 ​​짜증 난다!
jcollum

3

디렉토리와 그 내용을 삭제하려면 두 단계가 필요합니다. 먼저 내용을 삭제 한 다음 폴더 자체를 삭제하십시오. 잘못된 재귀 제거 항목에 대한 해결 방법을 사용하면 솔루션은 다음과 같습니다.

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

이 방법으로 상위 디렉토리도 제거 할 수 있습니다.


1
이것이 바로 받아 들여진 대답입니다. 추가 할 것이 있습니까?
Michael Hampton

1
그들은 받아 들인 대답이 디렉토리 자체를 삭제하지 않으므로 두 단계를 수행한다고 지적합니다.
폴 조지

2
Remove-Item원래 명시된 것과 같은 문제가로 배관을 명령. 같은 방법으로 비어 있지 않은 디렉토리 항목에서 우연히 발견 될 수 있습니다.
Dejan

@Dejan이 코드의 첫 줄이 작동하면이 디렉토리를 비울 수 없었습니까?
Ifedi Okonkwo 2016 년

1
이는 실패 가능성을 감소시킬 수 있지만 Remove-Item -Recurse여전히 관련되어 있다고 해도 실패 할 수 있습니다 . 기본 문제는 여전히 Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1부터 존재합니다 . 이 버그 보고서를 참조하십시오 .
mklement

3

어이. 많은 답변. 나는 솔직히이 모든 것을 선호합니다. 매우 간단하고 완벽하며 읽을 수 있으며 모든 Windows 시스템에서 작동합니다. .NET의 (신뢰할 수있는) 재귀 삭제 기능을 사용하며 어떤 이유로 실패하면 try / catch 블록으로 처리 할 수있는 적절한 예외가 발생합니다.

$fullPath = (Resolve-Path "directory\to\remove").ProviderPath
[IO.Directory]::Delete($fullPath, $true)

합니다 Resolve-Path상대 파일 경로를 해석 할 때 .NET은 현재 디렉토리를 인식하지 않기 때문에 라인이 중요하다. 그것은 내가 생각할 수있는 유일한 문제입니다.


2

이것이 내가 일한 것입니다.

$Target = "c:\folder_to_delete"

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

Remove-Item -Recurse -Force $Target

이 첫 번째 줄은 트리의 모든 파일을 삭제합니다. 두 번째는 상단을 포함하여 모든 폴더를 삭제합니다.


이는 실패 가능성을 감소시킬 수 있지만 Remove-Item -Recurse여전히 관련되어 있다고 해도 실패 할 수 있습니다 . 기본 문제는 여전히 Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1부터 존재합니다 . 이 버그 보고서를 참조하십시오 .
mklement


0

삭제되지 않는 디렉토리 에이 문제가있었습니다. 하위 폴더 중 하나가 손상되어 해당 하위 디렉토리를 이동하거나 이름을 바꾸려고 할 때 누락 된 내용에 대한 오류 메시지가 나타납니다. rm -Force를 사용하려고 시도했지만 동일한 오류가 발생했습니다.

나를 위해 일한 것은 "압축 후 파일 삭제"옵션을 선택한 상태에서 7-zip을 사용하여 부모 디렉토리를 압축하는 것이 었습니다. 압축되면 zip 파일을 삭제할 수있었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.