Início > Windows PowerShell > PoSh – Como compactar/descompactar arquivos?

PoSh – Como compactar/descompactar arquivos?

julho 4, 2015

Olá pessoALL,

Mais um vez eu estou aqui para dar uma dica de algo que é parte do dia a dia de qualquer IT-Pro, a compactação/descompactação de arquivos e de forma mais focada neste post, utilizando PowerShell (PoSh!).

Se você é um IT-Pro certamente já experimentou problemas por falta de espaço livre em volumes de servidores e é praticamente certo que em alguma destas ocasiões você determinou que o ofensor de espaço era uma aplicação gerando arquivos de log de forma não controlada e sem um ciclo de expurgo.

Provavelmente você deve ter tomado uma ação como deletar os arquivos após ter completa certeza que eles não são mais necessários ou então resolveu compactá-los, pois o responsável pelo recurso que os gerou informou que seria necessário preservá-los devido a alguma necessidade.

Sendo bem sincero… Eu detesto este tipo de situação onde você precisa tomar uma ação manual que poderia ser automatizada. Então, como eu posso resolver este tipo de situação que deveria ser resolvida pelo responsável da aplicação que está criando esta demanda de trabalho? Simples!

Vamos imaginar primeiramente a seguinte situação:

  • há um diretório C:\Logs\App1.
  • há uma aplicação chamada App1 que grava seus arquivos de log chamados App1_ddMMyyyy.log diariamente em C:\Logs\App1.
  • não há uma rotina de expurgo destes logs feita por App1.
  • há uma necessidade de preservar os arquivos por algum tempo.
  • o responsável pelo App1 informa que os logs precisam ser retidos por pelo menos 30 dias.

Como resolver este tipo de situação sem a necessidade de produtos de terceiros? PoSh + .Net Framework 4.5 são a solução!

Primeiramente deixe me informar que para tirar proveito deste tipo de solução você precisa ter no mínimo o PowerShell v3 instalado, caso contrário, não será possível o uso da solução proposta neste post. Se o seu ambiente atende ao requesito mínimo, vamos olhar o código abaixo:

Zip_Unzip_PoSh_0001

Agora vamos entender as partes envolvidas no código acima. Como já informado, há necessidade a ser atendida e uma solução a ser implementada, então vamos dar uma olhada na primeira parte do script.

$Source = “C:\Logs\App1”
$Destination = “C:\Logs\App1\ArchivedLogs_From_”+(Get-Date).AddDays(-7).ToString(‘ddMMyyyy’)+”_To_”+(Get-Date).ToString(‘ddMMyyyy’)+”.zip”

Sabemos que o diretório onde estão sendo armazenados os logs do App1 é C:\Logs\App1, então, vamos atribuir a uma variavel chamada $Source esse valor para melhor gerenciamento do código. Também precisamos de um arquivo .zip de saída onde os logs serão incluídos.

Por questões de organização, vou preservar o arquivamento deste .zip no mesmo diretório onde os logs estão e para compor seu nome, vou usar o seguinte padrão: App1_From_ddMMyyyy_To_ddMMyyyy.zip. Para chegarmos a este nome, vou utilizar o CmdLet Get-Date para obter a data atual e alguns dos métodos disponíveis deste CmdLet para formatar a saída de acordo com o que eu desejo e compor o nome do arquivo.

(Get-Date).AddDays(-7).ToString(‘ddMMyyyy’) significa obtermos a data atual (Get-Date), adicionar menos sete dias a data atual .AddDays(-7) e converter a saída deste comando para o formato ddMMyyyy .ToString(‘ddMMyyyy’). (Get-Date).ToString(‘ddMMyyyy’) obtem a data atual e a converte no formato ddMMyyyy.

Add-Type -AssemblyName “System.IO.Compression.FileSystem”

O comando acima carrega o namespace do .NET Framework 4.5 permitindo o uso de suas classes e de seus métodos no script. Para saber mais sobre este assembly, consulte a bibliotéca do MSDN – ZipFile Class.

$LogFiles  = Get-ChildItem “$Source” -Recurse -Include “*.log” | ? {$_.LastWriteTime -lt (Get-Date).AddDays(-7)}
$ZipFiles  = Get-ChildItem “$Source” -Recurse -Include “*.zip” | ? {$_.LastWriteTime -lt (Get-Date).AddDays(-30)}

A parte anterior utiliza o CmdLet Get-ChildItem na primeira linha para listar todos os arquivos com extensão .log dentro de C:\Logs\App1 onde a última data de escrita é inferior a sete dias e armazena o resultado na variavel $LogFiles.

Na segunda linha nós temos a mesma estrutura do comando, mas com duas diferenças: (1) a extensão e a (2) data de corte de trinta dias. Como informado, precisamos reter os últimas 30 dias, então, os arquivos .zip inferiores aos últimos trinta dias podem ser descartados e removidos.

If ($LogFiles -ne $Null) {
$ArchivedZip= [System.IO.Compression.ZipFile]::Open($Destination,”Update”)
ForEach ($LogFile in $LogFiles) {
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($ArchivedZip,$LogFile.FullName,$LogFile.Name,”optimal”)
Remove-Item $LogFile.FullName | Out-Null
}
$ArchivedZip.Dispose()
}

Aqui está a parte legal do script que é a funcionalidade de zip. Se a variável $LogFiles é diferente de nula, ou seja, há arquivos com data inferior a sete dias, nós vamos criar um arquivo .zip vazio usando a classe ZipFile, seu método Open ([System.IO.Compression.ZipFile]::Open($Destination,”Update”)) e prepará-lo para receber os arquivos de log para realizarmos o arquivamento.

Após este método ser executado, um arquivo será criado em C:\Logs\App1\ArchivedLogs_From_27062015_To_04072015.zip e uma referência para este arquivo será colocada na variável $ArchivedZip.

Utilizando o laço ForEach nós vamos percorrer todas as entradas existentes na variável $LogFiles e para cada entrada, vamos utilizar a classe ZipFileExtension e seu método CreateEntryFromFile “System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($ArchivedZip,$LogFile.FullName,$LogFile.Name,”optimal”)” para inserirmos em nosso arquivo zip os arquivos de log.

Em seguida vamos executar o comando Remove-Item para deletar literalmente o arquivo que foi arquivado no zip. Por fim, após todos os arquivos serem arquivos e removidos, vamos encerrar a operação no arquivo zip usando o método .Dispose(), caso contrário, não será possível abrir o arquivo zip e você poderá corrompê-lo perdendo seu conteúdo.

If ($ZipFiles -ne $Null) {
ForEach ($ZipFile in $ZipFiles) {
Remove-Item $ZipFile.FullName | Out-Null
}
}

Na parte final do código, vamos tratar dos arquivos zip de arquivamentos anteriores e garantir que se houver algum com data inferior a trinta dias, que este será removido ao final.

Por fim, e se precisarmos extrair estes arquivos? Como eu faria isto? A extração é algo simples e com o uso da classe ZipFile e seu método ExtractToDirectory é possível atender a esta necessidade.

$SourceZip  = “C:\Logs\App1\App1_From_ddMMyyyy_To_ddMMyyyy.zip”
$Destination = “C:\TEMP\App1”
[IO.Compression.ZipFile]::ExtractToDirectory($SourceZip, $Destination)

What about that? Let’s have some fun, huh!?

É impressionante, mas há poucos IT-Pros que teem conhecimento sobre este tipo de solução nativa do .Net Framework 4.5 em conjunto com PoSh.

Bem, este foi mais um post relacionado a PoSh e também sobre ações que fazem parte do dia a dia de qualquer IT-Pro.

Até o próximo post…

Referências:

System.IO.Compression Namespace

%d blogueiros gostam disto: