When I developed automssqlbackup, one of the key features was to optionally zip the generated database backup file.
I found solutions like this which essentially create an empty zip archive, then create a Shell.Application object to access this archive, and add files using the CopyHere or MoveHere methods of that object.
However, this approach has some severe drawbacks:
- Zip file creation and access via Shell.Application can collide occasionally, so that the COM object cannot access the zip file
- If such a collision occurs, the shell will display a message box which the user has to confirm/cancel, and the caller (the Powershell script, in this case) is not notified about the error situation
- The MoveHere method does not seem to *move* in the sense that the original file is deleted after being added to the zip archive
(short rant: this is automation the Microsoft way. Provide a programming interface, and if things go wrong, display a message box. Provide functionality as asynchronous operation and not tell the caller when it’s finished. If this was *real* automation, the caller would receive an error notification and a success notification from the callee, and the caller would decide how to react)
Since these effects showed up soon after I tested my script on different machines, it was clear that zipping had to be solved more reliably: using SharpZipLib.
First SharpZipLib is loaded into the Powershell script:
[System.Reflection.Assembly]::LoadFrom("C:\path-to\ICSharpCode.SharpZipLib.dll")
I found there are 2 simple ways to create a zip archive and add a file to it:
Using ZipFile.Create() and *Update()
$zip = [ICSharpCode.SharpZipLib.Zip.ZipFile]::Create($zipname)
$zip.BeginUpdate()
$zip.Add($filename)
$zip.CommitUpdate()
$zip.Close()
Quick and easy, but with a drawback: the filenames are stored including their original path information.
Using FastZip.CreateZip()
$zip = New-Object ICSharpCode.SharpZipLib.Zip.FastZip
$zip.CreateZip($zipname, $filenamedir, $false, "\.bak$")
$filenamedir is the base directory of all files to be included in the zip, followed by the recursive flag.
The final parameter is a bit tricky: it is named FileFilter, but it is not a DOS-like filter (“*.*”), but rather a regular expression being evaluated on each file. In the example above, all files with extension .bak are selected.