Sunday, April 11, 2010

Zip/Unzip with PowerShell

Files compression is a common task in software development and some times, some one need to write a script for a repetitive task like log files compression. In this case PowerShell is useful.

The following script show how we can doing a folder compression :


#Select folder for compression
function Select-FolderBrowserdDialog
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$objForm = New-Object System.Windows.Forms.FolderBrowserDialog
$objForm.RootFolder = "Desktop"
$Show = $objForm.ShowDialog()
If ($Show -eq "OK")
{
Return $objForm.SelectedPath
}
Else
{
Write-Error "Operation cancelled by user."
}
}

#Call function to open FolderBrowserdDialog
$dir = Select-FolderBrowserdDialog
#Set zip file name
$zipfilename = $dir + ".zip"
#is zip filz exists ?
if(-not (test-path($zipfilename))){
#Create zip file (the header required to convince Windows shell that this is really a zip file)
set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
#Set zip file writable
(dir $zipfilename).IsReadOnly = $false
}else{
#Throw exception if zipe file already exists
Throw "zipe file: " + $dir + ".zip" + " already exists"
}
#Instantiate com object "shell.application"
$shellApplication = new-object -com shell.application
#Set reference between Shell.Application namespace and a zip file
$zipPackage = $shellApplication.NameSpace($zipfilename)
#Get back information about the objects in the folder
$input = Get-ChildItem $dir
#Iterate over files information list
foreach($file in $input)
{
#get count of already zipped files
$zippedCount = $zipPackage.Items().Count
#compress the current file
#"CopyHere" take as parameters:
#file full name
#Some vOptions:
#8: Give the file being operated on a new name in a move, copy, or rename operation if a file with the target name already exists.
#64: for Responding with "Yes to All" for any dialog box that is displayed.
#256: Display a progress dialog box but do not show the file names.
$zipPackage.CopyHere($file.FullName,8 -and 16 -and 256)
#"CopyHere" function is asynchronous, so we have to wait until the current file is not compressed
while($zipPackage.Items().Count -lt ($zippedCount + 1)){
$maxLoops = 60*100 # 1 minutes
#The thread stop if file compression take more than 1 minute
if (--$maxLoops -le 0){
#Throw exception when file compression exceed 1 minute
Throw "timeout exceeded"
}
#Waiting 10 milliseconds for each file compression
Start-Sleep -milliseconds 10
}
}

Two functions are particularly interesting: "Select-FolderBrowserdDialog" and "CopyHere", the first one is for selecting a Folder path and the second is for adding files to a .zip archive (unfortunately this function is asynchronous, the while loop is to prevent the next file to be added at the same time).


On the other hand now we need to unzip the archive, the following script shows how to perform a folder decompression:


#Select zip file for decompression
function Select-OpenFileDialog
{
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
$objForm = New-Object System.Windows.Forms.OpenFileDialog
$objForm.InitialDirectory = "E:\"
$objForm.Filter = "Zip file (*.zip)|*.zip|All Files (*.*)|*.*"
$objForm.Title = $Title

$Show = $objForm.ShowDialog()
If ($Show -eq "OK")
{
Return $objForm.FileName
}
Else
{
Write-Error "Operation cancelled by user."
}
}
#Get selected zip file name
$zipfilename = Select-OpenFileDialog
#Get Directory full name
$destination = [System.IO.Path]::GetDirectoryName($zipfilename)
#is zip file exist ?
if(test-path($zipfilename))
{
#Instantiate com object "shell.application"
$shellApplication = new-object -com shell.application
#Set reference between Shell.Application namespace and a zip file
$zipPackage = $shellApplication.NameSpace($zipfilename)
#Set reference between Shell.Application namespace and a directory
$destinationFolder = $shellApplication.NameSpace($destination)
#decompress the zip file
#"CopyHere" take as parameters:
#zip file items
#Some vOptions:
#8: Give the file being operated on a new name in a move, copy, or rename operation if a file with the target name already exists.
#64: For Responding with "Yes to All" for any dialog box that is displayed.
#256: Display a progress dialog box but do not show the file names.
$destinationFolder.CopyHere($zipPackage.Items(),8 -and 16 -and 256)
}

In this article, we have seen how we can zip and unzip files by using PoweShell. I hope this article has inspired you !

The following links were helpful to me:

David Aiken article
Msdn learning resources


zip ZipUnzip.zip - 1.9 Kio

1 comment:

  1. I have seen a lot of tools for work with zip files. But one of them saved me - fix corrupt zip once. It restored many my corrupted zip archives within short time and without even trying. Besides I recommended it some of my friends.

    ReplyDelete