Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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?

share|improve this question
1  
Simply adding .zip to the end of a file doesn't make it a .zip archive. Are you using PowerShell 2.0 or 3.0? If you're using 3.0, it's a heck of a lot easier. –  MDMarra Dec 7 '12 at 15:53
    
@MDMarra - Yes, powershell 3 (developed on Win7, deployed on Server 2003), isn't that what the "-com shell.application" does? Or have I messed that up? –  SteB Dec 7 '12 at 15:58
    
See the bottom of this answer for how to do this in PS3 –  MDMarra Dec 7 '12 at 16:13
    
@MDMarra - I now get a "make sure that the assembly containing this type is loaded." error, I've tried "[System.AppDomain]::CurrentDomain.GetAssemblies()" but can't see a compression dll –  SteB Dec 7 '12 at 16:27
    
Sorry, do you have .NET 4.5 installed? It's actually not a native PS3 thing, but rather a .NET 4.5 thing. My mistake for assuming you'd have both installed. –  MDMarra Dec 7 '12 at 16:30

2 Answers 2

up vote 3 down vote accepted

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
    }
}
share|improve this answer
    
That looked good, but when I tried it nothing happened. I didn't get a zip file but I also didn't get any errors. Could you expand on what the Set-Content and ReadOnly = false lines do? –  SteB Dec 10 '12 at 9:47
    
The set-content line adds the file header and creates a 0 byte file, ReadOnly = $false ensures we can copy files into the file. –  nimizen Dec 10 '12 at 10:09
    
I've updated my answer - the $zipFilepath & $zipFilename weren't being joined correctly. –  nimizen Dec 10 '12 at 10:38
    
Sorry, it was my fault, I'd accidentally changed it to Test-Path-Path! That works great now. –  SteB Dec 10 '12 at 10:58

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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.