Como excluir recursivamente um diretório inteiro com o PowerShell 2.0?

308

Qual é a maneira mais simples de excluir com força um diretório e todos os seus subdiretórios no PowerShell? Estou usando o PowerShell V2 no Windows 7.

Aprendi com várias fontes que o comando mais óbvio Remove-Item $targetDir -Recurse -Force, não funciona corretamente. Isso inclui uma declaração na ajuda online do PowerShell V2 (encontrada usando Get-Help Remove-Item -Examples) que afirma:

... Como o parâmetro Recurse nesse cmdlet está com defeito, o comando usa o cmdlet Get-Childitem para obter os arquivos desejados e o operador de pipeline para passá-los ao cmdlet Remove-Item ...

Eu já vi vários exemplos que usam Get-ChildItem e o direcionam para Remove-Item , mas os exemplos geralmente removem alguns conjuntos de arquivos com base em um filtro, não em todo o diretório.

Estou procurando a maneira mais limpa de exibir um diretório inteiro, arquivos e diretórios filhos, sem gerar nenhuma mensagem de aviso do usuário usando a menor quantidade de código. Um one-liner seria bom se for fácil de entender.

Matt Spradley
fonte
2
PowerShell, eu sei, masRD /S /Q
Rubens Farias
possível duplicado: stackoverflow.com/questions/1667145/…
Rubens Farias
Eu não acho que é uma duplicata. Eu revi 1667145 antes de postar. Ele está perguntando por que o PowerShell não está definindo corretamente o parâmetro Recurse bool ao chamar a implementação do método Remove-Item de um provedor personalizado do PowerShell. Eu estava perguntando sobre o comportamento Remove-Item no que se refere ao provedor de sistema de arquivos incorporado.
22810 Matt Spradley
2
"RD / S / Q" parece não funcionar no PowerShell - diz "Remover item: Não foi possível encontrar um parâmetro posicional que aceita o argumento '/ q'."
BrainSlugs83
5
rdé um apelido para Remove-Itemno PowerShell. cmd /c "rd /s /q"funciona, no entanto.
CodeKizen #

Respostas:

510
Remove-Item -Recurse -Force some_dir

realmente funciona como anunciado aqui.

rm -r -fo some_dir

são apelidos abreviados que também funcionam.

Até onde eu entendi, o -Recurseparâmetro simplesmente não funciona corretamente quando você tenta excluir um conjunto de arquivos filtrados recursivamente. Por matar um único dir e tudo abaixo parece funcionar bem.

Joey
fonte
5
Eu acho que você está correto. Eu estava recebendo a mensagem "Não é possível remover o item em 'algum diretório' porque está em uso". erro e assumiu que era um problema com o algoritmo de recursão e foi procurar uma solução alternativa. Acontece que eu tive um processo que iniciei anteriormente no script que estava funcionando no diretório de destino. Quando o script foi alterado para aguardar o outro processo, o comando "Remove-Item -Recurse -Force" funciona. Sempre olhar no espelho primeiro :)
Matt Spradley
15
Descobri que preciso executar isso duas vezes ao executar em um diretório que contém subdiretórios. Na primeira vez, haverá muitos erros "O diretório não está vazio". Na segunda vez, ele é concluído sem erros.
Kristopher Johnson
5
Kristopher Johnson, eu recebo erros semelhantes com diversas ferramentas no Windows 7. Parece que a chamada de exclusão retorna antes que um arquivo ou pasta seja realmente removido, causando problemas às vezes. Isso parece acontecer no Explorer, Far, cmd e PowerShell.
Joey
2
@Joey "Parece que a chamada de exclusão retorna antes que um arquivo ou pasta seja realmente removido, causando problemas às vezes." -> Para esclarecimentos: a pasta pai não será excluída e ocorrerá o seguinte erro: "[pasta pai] não pode ser removida porque não está vazia." Vejo isso acontecer constantemente em unidades de rede (lentas). A única solução é a antiga: cmd /c rdconforme indicado abaixo.
Dior Josipovic 03/04
6
O que há nos erros "O diretório não está vazio"? serverfault.com/questions/199921/powershell-remove-force Talvez seja melhor obter o childitem * -include * .csv -recurse | remove-item não sei. Veja stackoverflow.com/a/1668471/206730
Kiquenet
39

Eu usei:

rm -r folderToDelete

Isso funciona para mim como um encanto (eu roubei do Ubuntu).

Tuan Jinn
fonte
Isso não requer cygwin, git ou alguma outra ferramenta que possa simular um shell bash no Windows?
Pete
19
@ Peter, não, ele não requer nada além do PowerShell. rmé um alias para Remove-Itema configuração padrão do PowerShell. Verifique a saída de Get-Alias rmpara mais detalhes. Ele -restá aproveitando o comportamento de correspondência parcial do PowerShell nos parâmetros. Desde Remove-Itemtem apenas a um parâmetro que começa com um 'r', -Recurse, -rcorresponde. Assim, a seguir tudo vai funcionar da mesma: rm -r, rm -re, Remove-Item -Recurse. (Note-se que nem rm -rfnem rm -r -fvai funcionar, mas rm -r -fo. Vontade -rfJogos sem parâmetros e -fpartidas mais do que uma.)
chwarr
1
Que tal isso. O alias do rm do Powershell para "Remove-Item -Recurse -Force some_dir" funciona melhor do que diretamente usando remove-item. Eu recebi os mesmos erros "Não é possível remover o item em 'some directory'. Alterno de remove-item para rm -r sem erros !?
Greg
Interessante. Eu tenho ferramentas cygwin na minha caixa e tentei rm -rf foldere, é claro, falhou. Inicialmente, votei negativamente na resposta (porque dizia Ubuntu). Graças ao comentário de @chwarr, tentei sem o fe ele pegou o alias em vez de rm binário. Desejo Tuan vai atualizar sua fonte (não sei se Tuan sabia que era um apelido ou realmente pensei que era o rm unix ;-)
Joshua Bola
2
Talvez seja porque eu uso o em -Rvez de -r(embora, até onde eu saiba, o PowerShell seja como o resto do Windows não faz distinção entre maiúsculas e minúsculas, portanto não deve fazer diferença), mas recebi um erro que as pastas que estou tentando excluir são não está vazio.
precisa saber é o seguinte
25

Ao excluir arquivos recursivamente usando um simples Remove-Item "folder" -Recurse, às vezes vejo um erro intermitente:[folder] cannot be removed because it is not empty.

Esta resposta tenta impedir esse erro excluindo individualmente os arquivos.

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

Um detalhe importante é a classificação de todos os itens pspath -Descendingpara que as folhas sejam excluídas antes das raízes. A classificação é feita no pspathparâmetro, pois tem mais chances de trabalhar para outros fornecedores que não o sistema de arquivos. O -Includeparâmetro é apenas uma conveniência se você deseja filtrar os itens a serem excluídos.

Ele é dividido em duas funções, pois acho útil ver o que estou prestes a excluir executando

Get-Tree some_dir | select fullname
John Rees
fonte
1
Ao resolver um problema usando o PowerShell nos scripts de construção do TFS, essa foi a resposta correta.
Rcabr
Esta é a solução para mim também. Tenha alguns pontos meu bom homem!
28916 Jammer
Trabalhou para mim. Não foi possível excluir o conteúdo de uma pasta recursivamente, mas sua solução funcionou para mim. graças
SheldonH
Esta é uma solução muito robusta
Max Jovem
Não sei por que a resposta aceita tem tantos votos - eu pessoalmente ainda recebo erros intermitentes usando o remove-item -recursePowershell v5, portanto, essa solução é a melhor para mim.
JonoB 25/02/19
13
rm -r ./folder -Force    

... trabalhou para mim

stevethecollier
fonte
11

Tente este exemplo. Se o diretório não existir, nenhum erro será gerado. Você pode precisar do PowerShell v3.0.

remove-item -path "c:\Test Temp\Test Folder" -Force -Recurse -ErrorAction SilentlyContinue
Steve
fonte
7

Use o comando DOS da velha escola:

rd /s <dir>
Peter Mortensen
fonte
Se isso faz parte de um script, você precisaria usar /q(modo silencioso, não pergunte se está OK para remover uma árvore de diretórios com / S) também.
Wildeyes
6

Por alguma razão, a resposta de John Rees às vezes não funcionou no meu caso. Mas isso me levou na seguinte direção. Primeiro, tento excluir o diretório recursivamente com a opção buggy -recurse. Depois, desço para todos os subdiretórios restantes e apago todos os arquivos.

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
fonte
Você pode reproduzir o erro ao executar minhas funções? Gostaria de saber para melhorá-los.
John Rees
Desculpe, não se lembre da configuração exata. : / Eu acho que foi quando vários subdiretórios estavam envolvidos. Ocorreu que a chamada para "Remove-Item -force -recurse" não excluiu todos os arquivos e, nesse caso, a última Remove-Tree falhou porque o diretório não estava vazio. Foi por isso que criei a nova solução para experimentar primeiro a versão interna do buggy (-force) e depois descer manualmente para cada diretório e excluir "manualmente" o que resta. Esta versão está em uso regularmente e até agora está funcionando. A única causa da falha foi quando um programa ainda mantém um identificador em um diretório.
jdoose
5

Para evitar os erros "O diretório não está vazio" da resposta aceita, basta usar o bom e antigo comando do DOS, conforme sugerido anteriormente. A sintaxe completa do PS pronta para copiar e colar é:

& cmd.exe /c rd /S /Q $folderToDelete
Dejan
fonte
3
Ainda dá erro "O diretório não está vazio" para pastas !?
Oncel Umut TURER
2

Adotei outra abordagem inspirada em @ john-rees acima - especialmente quando sua abordagem começou a falhar para mim em algum momento. Recursalize basicamente a subárvore e classifique os arquivos pelo tamanho do caminho - exclua do maior para o menor

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

Em relação à magia -LiteralPath, aqui está outra pegadinha que pode estar atingindo você: https://superuser.com/q/212808

Peter McEvoy
fonte
2
del <dir> -Recurse -Force # I prefer this, short & sweet

OU

remove-item <dir> -Recurse -Force

Se você tem um diretório enorme, o que eu costumo fazer é

while (dir | where name -match <dir>) {write-host deleting; sleep -s 3}

Execute isso em outro terminal do PowerShell e ele irá parar quando terminar.

Gajendra D Ambi
fonte
Admito que sua ideia com o monitoramento pode ser útil, mas é apenas diferente de apenas imprimir uma mensagem quando terminar e, caso tenha havido algum problema ao interromper o Remove-Item, seu loop nunca terminará.
Raúl Salinas-Monteagudo
@ RaúlSalinas-Monteagudo é verdade, mas é definitivamente para prod ou cenário de uso autônomo. Ele deve ser pequeno o suficiente para alguém lembrar e digitar em movimento e não executar um sofisticado arquivo .ps1 em apenas um diretório.
Gajendra D Ambi
2

A exclusão de uma árvore de pastas inteira às vezes funciona e às vezes falha com erros de "Diretório não vazio". Subseqüentemente, tentar verificar se a pasta ainda existe pode resultar em erros "Acesso negado" ou "Acesso não autorizado". Não sei por que isso acontece, embora algumas informações possam ser obtidas com essa postagem do StackOverflow .

Consegui solucionar esses problemas especificando a ordem em que os itens da pasta são excluídos e adicionando atrasos. O seguinte funciona bem para mim:

# 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

Um artigo do Microsoft TechNet Usando propriedades calculadas no PowerShell foi útil para obter uma lista de subpastas classificadas por profundidade.

Problemas semelhantes de confiabilidade com RD / S / Q podem ser resolvidos executando DEL / F / S / Q antes de RD / S / Q e executando o RD uma segunda vez, se necessário - idealmente com uma pausa no meio (por exemplo, usando ping como mostrado abaixo).

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
fonte
1

Realmente simples:

remove-item -path <type in file or directory name>, press Enter
DusanV
fonte
Você também deve oferecer um exemplo de execução.
indivisível
1

Outro truque útil:

Se você encontrar muitos arquivos com a mesma convenção de nome ou com um nome semelhante (como arquivo mac com nome de prefixo de ponto ... esse famoso arquivo pulltion), poderá removê-los facilmente com uma única linha do powershell, como segue:

ls -r .* | rm

Essa linha removerá todos os arquivos com um ponto no início do nome dentro do diretório atual e todos os arquivos com as mesmas circunstâncias em outras pastas dentro desse diretório. Esteja ciente disso ao usá-lo. : D

Daniel Alberto Lepe Ayala
fonte
Por que não usar rm -rf .*? Não tenho o PowerShell para testar, mas acho que funcionará.
Vini.g.fer
1
É fácil; se você apenas remover o "| rm" do comando, poderá ver um panorama inteiro do que você deseja excluir, depois de ter certeza, poderá concluir o comando.
Daniel Alberto Lepe Ayala #
Por exemplo, para copiar os arquivos que são empacotados com pontos, (como os mac), e ver que tengan é proponente de oculto, use-os: ls -r -h. * | rm
Daniel Alberto Lepe Ayala
1

Para excluir o conteúdo completo, incluindo a estrutura de pastas, use

get-childitem $dest -recurse | foreach ($_) {remove-item $_.fullname -recurse}

O -recurseitem adicionado remove-itemgarante que os avisos interativos sejam desativados.

Steve Simon
fonte
-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"
}

Escreveu o acima para limpar alguns arquivos de log sem excluir o diretório pai e isso funciona perfeitamente!

Tom Stevenson
fonte
-2
rm -r <folder_name>
c:\>rm -r "my photos"
user3008
fonte
1
Por favor, explique que ainda de forma que outros possam aprender com a sua resposta
Nico Haase