Apagar arquivos de determinadas extensões usando apenas o Windows Powershell - HOWTO

Olá,

Vou postar agora a solução para um problema que aparece nos grupos de notícias/fóruns/listas de email a cada 15 ou 30 dias. É um problema tão recorrente que esta é a terceira vez que escrevo sobre isso. Tenho uns dois scripts em VBScript publicados em algum lugar com a solução também.

Para mostrar como é fácil mexer com Windows Powershell, vou fazer um how-to de como pensar num script pra ele:

Primeiramente, vamos listar os arquivos de um local qualquer. Isso, com o Powershell, pode ser feito da seguinte forma:

dir \\192.168.0.1\c$

Simples. Basta usar o compartilhamento administrativo. Agora, vamos adicionar duas coisas: listagem recursiva, em todas as subpastas, e também que o script não exiba nenhuma mensagem de erro caso não consiga listar algum dos arquivos.

dir \\192.168.0.1\c$ -recurse -errorAction silentlyContinue

Agora, vamos filtrar somente para os que possuem extensão .MP3:

dir \\192.168.0.1\c$ -recurse -errorAction silentlyContinue | where {$_.extension -eq '.mp3'}

Vale lembrar que $_ é a variável que representa cada um dos arquivos dentro do bloco que o where-object analisa. Ele vai pegar todos os arquivos que sairem do comando dir, e passar somente os que tiverem extensão .MP3. Agora, vamos deixar mais genérico: quero que sejam várias extensões. Isso precisará de mais linhas:

$h = new-object System.Collections.Specialized.StringCollection
$h.Add('.mp3')
$h.Add('.avi')
$h.Add('.iso')
dir \\192.168.0.1\c$ -recurse -errorAction silentlyContinue | where {$h.contains($_.extension)}

Notem que eu usei, para facilitar, um objeto da classe StringCollection do .Net. Dá pra fazer de outras 6x10^23 formas diferentes, e eu achei que essa era a mais didática. Um StringCollection nada mais é do que uma estrutura para armazenamento de Strings, onde só me interessa saber se uma dada string já está lá ou não. Agora, vamos apagar os arquivos.

$h = new-object System.Collections.Specialized.StringCollection
$h.Add('.mp3')
$h.Add('.avi')
$h.Add('.iso')
dir \\192.168.0.1\c$ -recurse -errorAction silentlyContinue
| where {$h.contains($_.extension)}
| foreach {rm $_ -whatIf}

Fiz duas coisas: quebrei a última linha em 3 para facilitar a leitura, e adicionei mais um comando nessa linha, o comando foreach. Ele executa o bloco para cada arquivo recebido pelo pipe. Para testar, coloquei o parametro -whatIf, que, ao invés de apagar, mostra as ações que vão ser tomadas pelo Powershell. Isso é útil para testar sem tomar nenhum susto antes de colocar em produção. Agora a parte mais legal: vamos fazer isso para várias máquinas. Basta colocar o IP ou nome delas num arquivo texto qualquer, uma em cada linha:

ts-server
webserver
192.168.0.17
127.0.0.1

E listar esse arquivo, fazendo algumas modificações:

$h = new-object System.Collections.Specialized.StringCollection
$h.Add('.mp3')
$h.Add('.avi')
$h.Add('.iso')
foreach ($machine in (cat lista-arquivos.txt)){
dir ('\\'+ $machine + '\c$') -recurse -errorAction silentlyContinue
| where {$h.contains($_.extension)}
| foreach {rm $_}
}

Fácil, não? Com Powershell é tudo muito intuitivo. Basta montar seu script com calma.

Até a próxima!

Categorias dessa postagem: ,

Comentários

rodrigo.okida@gmail.com : Vinicius,
Este script nao rodou no meu servidor. Ele parou na linha | where {$h.contains($_.extension)}

Deu o seguinte erro:

PS T:\> |where {$h.contains($_.extension)}
An empty pipe element is not permitted.
At line:1 char:2
+ |w <<<< here {$h.contains($_.extension)}
PS T:\> |foreach {rm $_ -whatIf} [3/7/07 17:41 - link]

Vinicius Canto : Olá,


você executou as linhas que estão acima deste comando? Elas são necessárias para inicializar a Coleção de strings com as extensões que você quer pegar.

[]s,

Vinicius Canto
MVP Scripting 2x [5/7/07 23:47 - link]

Vinicius Canto : Só agora percebi minha falha... o pipe deve vir na linha de cima, de forma a permitir que o comando continue na linha seguinte.


[]s,

Vinicius Canto
MVP Windows Server - Admin Frameworks [28/7/07 16:37 - link]

Anônimo : Vinicius, saudações.

Eu entendi o funcionamento mas isso não tira faz deixar de ser um zero à esquerda em programação.

Se eu quiser apagar todos os arquivos e pastas ANTERIORES a uma data específica, onde mexo?

Grato pela atenção e pela iniciativa!
Fabio Ramiro [31/8/07 13:08 - link]

Vinicius Canto : Veja esse link:

http://viniciuscanto.blogspot.com/2006/12/apagando-arquivos-antigos-no-powershell.html [9/9/07 19:55 - link]

Edson : Ola Caro Vinicius Canto
Como posso fazer a linha de comando que deleta todos os arquivo de video e musica de tal ip?
Estou com certa dificuldade em entender o assunto postado.

Atenciosamente Edson Shintaro Watanabe [13/9/07 13:51 - link]

Cyrillo : Achei muito interessante o script!

Só que na hora de apagar os arquivos dá um erro! Segue ele:

Remove-Item : Nao é possivel localizar o caminho C:\teste.iso porque ele nao existe

E fica dando esse erro em todos os arquivos que ele acha. Ele procura na rede, mas na verdade, quando vai apagar, pensa que o arquivo tá localmente! Como faz pra consertar isso?

Obrigado! [16/4/08 16:20 - link]

Vinicius Canto : Olá Cyrillo,


realmente o comando tem um erro. O correto é rm $_.fullname na parte do script que apaga o arquivo.

O motivo do problema ocorrer é simples: como o dir pega arquivos recursivamente, o comando rm não vai funcionar somente com o nome do arquivo (indicado na variável $_). Nesse caso, como $_ é um objeto, basta usar a propriedade fullname dele.

Até mais! [25/4/08 12:06 - link]

Vinicius Canto : Olá Edson,


não sei se você compreendeu o script que eu montei. Note que você precisa ter um arquivo de texto com o nome ou IP das máquinas a serem "varridas". Basta criar o arqiuvo, salvar, e executar o script.

[]s,

Vinicius [25/4/08 12:10 - link]

Anônimo : Com os inúmeros vírus de Pen drive pensei em um script que delete as extensões .exe, .inf, .dll, .ini, .com ai pensei em fazer o comando del /q/f *.extensão. Só que estou com um probleminha em apagar os com extensão .ini e .bin. Como vc faria um script para isso? [29/5/08 00:50 - link]

Carlos Tavares : Vinicius,
Tentei mesmo fazendo a correção do $_.fullname e mesmo assim nao deletou. coloquei até o parametro force e nada de funcionar. Até adaptei seu script para apenas buscar *.mp3 mas nao vai... Eu listo o caminho dos arquivos a excluir, mas nao consigo excluir. Poderia ser permissao? O problema é que nao volta erro de nada. [29/8/08 19:57 - link]

Júnior Casado : Bom dia Vinicius, criei esse script para listar arquivos de vários micros da minha rede, mas gostaria que não listasse o c:\Arquivos de Programas e outra pasta padrão, tem como? Se tiver algum script em VBScript também já me ajuda.

$h = new-object System.Collections.Specialized.StringCollection
$h.Add('.doc')
$h.Add('.xls')
$h.Add('.pdf')
$h.Add('.pps')
$h.Add('.ppt')
$h.Add('.odt')
$h.Add('.ods')
dir \\cad2433\c$ -recurse -errorAction silentlyContinue | where {$h.contains($_.extension)} | out-file c:\temp\cad2433.txt [25/9/08 08:27 - link]

Marcelo Oliveira : Olá Vinicius..
Estou precisando de algo tipo esse script que você escreveu, mas preciso de alguns detalhes diferentes, queria saber se você poderia me ajudar, por favor.
Tenho 5 servidores e as vezes preciso apagar a pasta de perfil de um usuario dos 5 servidores. PRecisava de um script que eu colocasse a matricula do usuario e ele automaticamente ja apagasse nos 5 servidores. Tem como isso? Muito obrigado pelo apoio [20/11/08 14:12 - link]

Vinicius Canto : Por partes:

Anônimo: coloque um dir -force e um del -force no script que eu coloquei no post original.

Carlos: Não. Se fosse permissão, o PowerShell mostraria um erro. Tente apagar com o parâmetro -whatIf no comando que apaga os arquivos para ver se o script está correto.

Júnior: veja o parâmetro -exclude do comando dir.

Marcelo: 1) evite o crosspost. não é legal em foruns, nem em blogs. 2) a descrição ainda tá muito vaga e eu não tenho conhecimento nenhum do seu ambiente. O que é a Matrícula? Onde ela tem que ir? Pra apagar em vários servidores você pode usar o comando foreach-object do powershell em conjunto com o script que eu coloquei no post. Procure também nos posts antigos que esse tipo de dúvida já foi respondida.


[]s,

Vinicius [20/11/08 21:27 - link]

Anônimo : Parabéns muito bom!
Essa é uma ótima dica e super explicada! [12/4/11 10:57 - link]