Buộc loại bỏ các tệp và thư mục trong PowerShell đôi khi không thành công, nhưng không phải lúc nào cũng


33

Tôi đang cố gắng xóa một thư mục đệ quy với rm -Force -Recurse somedirectory, tôi nhận được một số lỗi "Thư mục không trống". Nếu tôi thử lại cùng một lệnh , nó sẽ thành công.

Thí dụ:

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>

Tất nhiên, điều này không xảy ra luôn . Ngoài ra, điều đó không xảy ra chỉ với các _svnthư mục và tôi không có bộ đệm TortoiseSVN hoặc bất cứ thứ gì tương tự để không có gì chặn thư mục.

Có ý kiến ​​gì không?

Câu trả lời:


31

help Remove-Item nói:

Tham số Recurse trong lệnh ghép ngắn này không hoạt động đúng.

Vì tham số Recurse trong lệnh ghép ngắn này bị lỗi, nên lệnh sử dụng lệnh ghép ngắn Get-Childitem để lấy các tệp mong muốn và nó sử dụng toán tử đường ống để chuyển chúng đến lệnh ghép ngắn Loại bỏ.

và đề xuất phương án này làm ví dụ:

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

Vì vậy, bạn nên đường ống get-childitem -recursevào remove-item.


Cảm ơn. Chỉ tìm thấy chủ đề này từ năm 2006: vistax64.com/powershell/ Nhật có vẻ như Microsoft không thực sự quan tâm đến việc sửa lỗi này.
Mauricio Scheffer

@mausch: Xem phần này gần đây hơn, nhưng vẫn chưa được giải quyết, tham khảo: Xóa-Mục -Recurse
Tạm dừng cho đến khi có thông báo mới.

nếu bạn thực hiện duyệt và xóa, trước tiên bạn sẽ phải duyệt qua các thư mục con và các tệp của chúng.
fschwiet

2
Ít nhất là tài liệu nói rằng nó không hoạt động.
derekerdmann

6
Tôi đã phải đặt cả hai cờ-Force -recurse cho Remove-Item, nếu không nó sẽ khiến tôi phải nhắc "vui lòng xác nhận" Get-ChildItem -Path $ Destination -Recurse | Loại bỏ vật phẩm-lực lượng -recurse
MiFreidgeim SO-ngừng trở thành ác quỷ

17

@JamesCW: Vấn đề vẫn tồn tại trong PowerShell 4.0

Tôi đã thử một cách giải quyết khác và nó đã hoạt động: sử dụng cmd.exe:

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

1
Tốt cũ / s / q!
JamesCW

Tôi đã thử mọi biến thể của Get-ChildItem; thử lại các vòng lặp; gọi iisresettrước khi xóa và dường như không có gì đáng tin cậy . Tôi sẽ thử cái này, mặc dù khi tôi lần đầu tiên nhìn thấy nó, tôi đã chùn bước khi có DOS bên trong Powershell của mình ...
Peter McEvoy

Thật không may, rd /sthất bại quá liên tục (mặc dù dường như ít thường xuyên hơn Remove-Item): github.com/Microsoft/console/issues/309
mkuity 27/11/18

Nó không giống như dấu gạch chéo của c đối với tôi. Bạn có phải đặt trước nó bằng powershell -command và trích dẫn một phần cmd.exe không? Tôi nhận được "Bạn phải cung cấp biểu thức giá trị theo sau toán tử '/'." "Mã thông báo bất ngờ 'c' trong biểu thức hoặc tuyên bố. Nó giống với quyền hạn -command ở phía trước. Có / cần thoát không?
Michele

7

ETA 20181217: PSVersion 4.0 trở lên vẫn sẽ thất bại trong một số trường hợp, xem câu trả lời thay thế của Mehrdad Mirrezabáo cáo lỗi được gửi bởi mkuity

mkuity cung cấp giải pháp Proof of Concept tại câu trả lời SO này , vì lỗi đang chờ sửa chữa chính thức

Phiên bản mới của PowerShell( PSVersion 4.0) đã giải quyết vấn đề này hoàn toàn và Remove-Item "targetdirectory" -Recurse -Forcehoạt động mà không gặp vấn đề về thời gian.

Bạn có thể kiểm tra phiên bản của mình bằng cách chạy $PSVersiontabletừ trong ISE hoặc PowerShelldấu nhắc. 4.0 là phiên bản đi kèm Windows 8.1Server 2012 R2, và nó cũng có thể được cài đặt trên các phiên bản Windows trước.


5
Vẫn xảy ra với tôi trong PowerShell 4.0
ajbeaven

10
Vẫn xảy ra trong PowerShell v5 !!!!! 11 !! 1! 1 !!!
Richard Hauer

@RichardHauer giờ tôi chỉ bối rối
JamesCW

2
@JamesCW Tôi đã chuyển đổi thành rdphiên bản. Ngoài việc thực sự hoạt động, nó còn nhanh hơn khoảng 3 lần
Richard Hauer

Sự cố chưa được khắc phục kể từ Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - xem báo cáo lỗi này . Mặc dù rd /scó thể thất bại ít thường xuyên hơn, nó cũng bị hỏng - xem báo cáo lỗi này .
mkuity

4

Cập nhật : Dường như có kế hoạch làm cho các API loại bỏ mục hệ thống tệp Windows đồng bộ hóa, nhưng chúng không đồng bộ kể từ phiên bản Windows 10 1903 - xem nhận xét này trên GitHub .


Các câu trả lời hiện có giảm thiểu vấn đề, để nó ít xảy ra hơn, nhưng chúng không giải quyết được nguyên nhân gốc rễ , đó là lý do tại sao các thất bại vẫn có thể xảy ra.

Remove-Item -Recursecuối cùng là không đồng bộ , vì các phương thức API Windows để xóa tệp và thư mục vốn không đồng bộRemove-Itemkhông giải thích được điều đó.

Điều này không liên tục, biểu hiện không thể đoán trước theo một trong hai cách:

  • Trường hợp của bạn: Việc tự xóa một thư mục không trống có thể thất bại, nếu việc xóa thư mục con hoặc tệp trong đó chưa hoàn thành trước thời điểm một nỗ lực được thực hiện để xóa thư mục mẹ.

  • Ít phổ biến hơn: Việc tạo lại một thư mục bị xóa ngay sau khi xóa có thể thất bại, vì việc xóa có thể chưa hoàn thành trước thời gian tạo lại được thực hiện.

Các vấn đề không chỉ ảnh hưởng của PowerShell Remove-Item, mà còn cmd.exe'srd /s cũng như .NET của[System.IO.Directory]::Delete() :

Kể từ Windows PowerShell v5.1 / PowerShell Core 6.2.0- cmd.exepreview.1 / 10.0.17134.407 / .NET Framework 4.7.03056, .NET Core 2.1, không Remove-Item, cũng không rd /s, cũng không [System.IO.Directory]::Delete()hoạt động đáng tin cậy , vì chúng không thể giải thích cho sự không đồng bộ hành vi của các chức năng loại bỏ tệp / thư mục API của Windows :

Để biết chức năng PowerShell tùy chỉnh cung cấp cách giải quyết đồng bộ đáng tin cậy , hãy xem câu trả lời SO này .


Khi xử lý các tệp mà việc xóa là chắc chắn:while($true) { if ( (Remove-Item [...] *>&1) -ne $null) { Start-Sleep 0.5 } else { break } }
Farway

3

Câu trả lời hiện tại sẽ không thực sự xóa một thư mục, chỉ là con của nó. Hơn nữa, nó sẽ có vấn đề với các thư mục lồng nhau vì nó sẽ lại cố gắng xóa một thư mục trước nội dung của nó. Tôi đã viết một cái gì đó để xóa các tập tin theo đúng thứ tự, vẫn sẽ có cùng một vấn đề mặc dù đôi khi thư mục sẽ vẫn còn xung quanh sau đó.

Vì vậy, bây giờ tôi sử dụng một cái gì đó sẽ bắt ngoại lệ, chờ đợi và thử lại (3 lần):

Hiện tại tôi đang sử dụng cái này:

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
Điều này là tốt nhưng tôi vẫn có vấn đề với nó. Nếu lệnh mkdir chạy trước khi hệ thống hoàn thành lệnh rm, nó có thể ném System.UnauthorizedAccessException với một FullQualifiedErrorId của ItemExistsUnauthorizedAccessError. Tức là, thư mục chưa bị xóa bởi HĐH (trên ổ cứng chậm của tôi). Vì vậy, lỗi đó cũng cần phải được bắt. Và đó là lỗi không kết thúc, do đó ErrorAction cần được đặt thành Dừng. Tôi cũng đặt lệnh rm trong khối thử, chỉ trong trường hợp có lỗi IO thoáng qua khi xóa.
Mark Lapierre

Tôi không thể tin điều này thậm chí phải được thực hiện. Chết tiệt, Powershell hút!
jcollum

3

Để xóa thư mục và nội dung của nó mất hai bước. Đầu tiên xóa nội dung, sau đó là thư mục chính nó. Sử dụng cách giải quyết cho mục xóa đệ quy bị lỗi, giải pháp sẽ như thế này:

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

Bằng cách này bạn cũng có thể loại bỏ thư mục cha.


1
Đây chính xác là những gì câu trả lời được chấp nhận nói. Bạn có thêm cái gì nữa không?
Michael Hampton

1
Họ đang chỉ ra rằng câu trả lời được chấp nhận không xóa chính thư mục, do đó phải mất hai bước.
Paul George

2
Các Remove-Itemlệnh đường ống của bạn vào có cùng một vấn đề rằng tuyên bố ban đầu. Nó có thể vấp ngã trên một mục thư mục không trống theo cùng một cách.
Dejan

@Dejan Thư mục này không thể để trống nếu dòng đầu tiên của mã này hoạt động, phải không?
Ifedi Okonkwo

1
Mặc dù điều này có thể làm giảm khả năng thất bại, nhưng nó vẫn có thể thất bại, do Remove-Item -Recursevẫn còn liên quan. Vấn đề cơ bản vẫn tồn tại kể từ Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - xem báo cáo lỗi này .
mkuity 28/11/18

3

Trời ạ. Rất nhiều câu trả lời. Tôi thực sự thích cái này hơn tất cả chúng. Nó cực kỳ đơn giản, đầy đủ, dễ đọc và hoạt động trên mọi máy Windows. Nó sử dụng chức năng xóa đệ quy (đáng tin cậy) của .NET và nếu vì một lý do nào đó, nó sẽ ném ra một ngoại lệ thích hợp có thể được xử lý bằng khối thử / bắt.

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

Lưu ý rằng Resolve-Pathdòng này rất quan trọng vì .NET không biết thư mục hiện tại của bạn khi giải quyết các đường dẫn tệp tương đối. Đó là về Gotcha duy nhất tôi có thể nghĩ ra.


2

Đây là những gì tôi đã làm việc:

$Target = "c:\folder_to_delete"

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

Remove-Item -Recurse -Force $Target

Dòng đầu tiên này xóa tất cả các tệp trong cây. Thứ hai xóa tất cả các thư mục bao gồm cả trên cùng.


Mặc dù điều này có thể làm giảm khả năng thất bại, nhưng nó vẫn có thể thất bại, do Remove-Item -Recursevẫn còn liên quan. Vấn đề cơ bản vẫn tồn tại kể từ Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.1 - xem báo cáo lỗi này .
mkuity


0

Tôi đã có vấn đề này với một thư mục sẽ không xóa. Tôi thấy rằng một trong những thư mục con đã bị hỏng và khi tôi cố gắng di chuyển hoặc đổi tên thư mục con đó, tôi nhận được một thông báo lỗi nói điều gì đó về việc nó bị mất. Tôi đã thử sử dụng rm -Force và gặp lỗi tương tự như bạn đã làm.

Điều làm việc cho tôi là nén thư mục gốc bằng cách sử dụng 7-zip với tùy chọn "Xóa tệp sau khi nén". Khi nó được nén, tôi có thể xóa tệp zip.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.