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
- CopyHere and MoveHere execute asynchronously. The caller does not receive any feedback when the operation is complete, and has to query the number of files in the archive to find out.
(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:
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.
$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.