Zipping only files using powershell

I'm trying to zip all the files in a single directory to a different folder as part of a simple backup routine.

The code runs ok but doesn't produce a zip file:

$srcdir = "H:\Backup"
$filename = "test.zip"
$destpath = "K:\"

$zip_file = (new-object -com shell.application).namespace($destpath + "\"+ $filename)
$destination = (new-object -com shell.application).namespace($destpath)

$files = Get-ChildItem -Path $srcdir

foreach ($file in $files) 
{
    $file.FullName;
    if ($file.Attributes -cne "Directory")
    {
        $destination.CopyHere($file, 0x14);
    }
}

Any ideas where I'm going wrong?


Solution 1:

This works in V2, should work in V3 too:

$srcdir = "H:\Backup"
$zipFilename = "test.zip"
$zipFilepath = "K:\"
$zipFile = "$zipFilepath$zipFilename"

#Prepare zip file
if(-not (test-path($zipFile))) {
    set-content $zipFile ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
    (dir $zipFile).IsReadOnly = $false  
}

$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipFile)
$files = Get-ChildItem -Path $srcdir | where{! $_.PSIsContainer}

foreach($file in $files) { 
    $zipPackage.CopyHere($file.FullName)
#using this method, sometimes files can be 'skipped'
#this 'while' loop checks each file is added before moving to the next
    while($zipPackage.Items().Item($file.name) -eq $null){
        Start-sleep -seconds 1
    }
}

Solution 2:

I discovered 2 additional ways to do this and am including them for reference:

Using the .Net framework 4.5 (as suggested by @MDMarra):

[Reflection.Assembly]::LoadWithPartialName( "System.IO.Compression.FileSystem" )
[System.AppDomain]::CurrentDomain.GetAssemblies()
$src_folder = "h:\backup"
$destfile = "k:\test.zip"
$compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
$includebasedir = $false
[System.IO.Compression.ZipFile]::CreateFromDirectory($src_folder, $destfile, $compressionLevel, $includebasedir)

This worked great on my Win7 development machine and is probably the best way to do this, but .Net 4.5 is only supported on the Windows Server 2008 (or later), my deployment machine is Windows Server 2003.

Using a command-line zip tool:

function create-zip([String] $aDirectory, [String] $aZipfile)  
{  
  [string]$PathToZipExe = "K:\zip.exe";  
  & $PathToZipExe "-r" $aZipfile $aDirectory;  
}

create-zip "h:\Backup\*.*" "K:\test.zip"

I downloaded info-zip and called it with the source and destination locations as parameters.
This worked fine & was very easy to set up, but required an external dependency.