142

I have a batch file that outputs a text file. I want to zip it too.

This will be used in an uncontrolled environment, so I can't make assumptions about the presence of third-party software products such as 7-Zip. This needs to use Windows' now-built-in capability to zip files.

Franck Dernoncourt
  • 24,246
  • 64
  • 231
  • 400
Aaron Bush
  • 1,563

12 Answers12

96

Here is an all batch file solution (a variation of my other answer) that will zip a file named c:\ue_english.txt and put it in C:\someArchive.zip:

set FILETOZIP=c:\ue_english.txt

set TEMPDIR=C:\temp738
rmdir %TEMPDIR%
mkdir %TEMPDIR%
xcopy /s %FILETOZIP% %TEMPDIR%

echo Set objArgs = WScript.Arguments > _zipIt.vbs
echo InputFolder = objArgs(0) >> _zipIt.vbs
echo ZipFile = objArgs(1) >> _zipIt.vbs
echo CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" ^& Chr(5) ^& Chr(6) ^& String(18, vbNullChar) >> _zipIt.vbs
echo Set objShell = CreateObject("Shell.Application") >> _zipIt.vbs
echo Set source = objShell.NameSpace(InputFolder).Items >> _zipIt.vbs
echo objShell.NameSpace(ZipFile).CopyHere(source) >> _zipIt.vbs
echo wScript.Sleep 2000 >> _zipIt.vbs

CScript  _zipIt.vbs  %TEMPDIR%  C:\someArchive.zip

pause

Write access is required to the parent of the folder stored in TEMPDIR. As this is often not the case for the root of drive C TEMPDIR may have to be changed.

Write access is also required for the folder the .bat script is in (as it generates a file there).

Also, please note that the file extension for the compressed file must be .zip. Attempts to use another extension may result in a script error. Instead, generate the .zip file and rename it.

Oreo
  • 131
  • 4
54

Windows 10 build 17063 or later is bundled with tar.exe which is capable of working with ZIP files from the command line.

tar.exe -xf archive.zip

Or to create a ZIP archive:

tar.exe -a -cf Test.zip Test
Frederik
  • 103
venimus
  • 2,488
41

It is possible to zip files without installation of any additional software (I have tested it). The solution is:

Run this in a command-line window to create a ZIP file named C:\someArchive.zip containing all files in folder C:\test3:

CScript  zip.vbs  C:\test3  C:\someArchive.zip

Where file zip.vbs contains:

' Get command-line arguments.
Set objArgs = WScript.Arguments
Set FS = CreateObject("Scripting.FileSystemObject")
InputFolder = FS.GetAbsolutePathName(objArgs(0))
ZipFile = FS.GetAbsolutePathName(objArgs(1))

' Create an empty ZIP file. CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)

Set objShell = CreateObject("Shell.Application")

Set source = objShell.NameSpace(InputFolder).Items

objShell.NameSpace(ZipFile).CopyHere(source)

' Required to let the ZIP command execute ' If this script randomly fails or the ZIP file is not complete, ' just increase to more than 2 seconds wScript.Sleep 2000

I haven't tested it for paths and file names containing spaces. It may work if quotes are put around the command line parameters.


How it works: the built-in zip functionality in Windows (Windows XP and later?) is exposed through COM interfaces from the Windows shell, explorer.exe - that is the "Shell.Application" part. This COM interface can be used from a VBScript script because such a script can access COM components. To make the script fully self-contained it creates an empty ZIP file to get started (one could also create an empty ZIP file and copy it to the target system along with the VBScript script).

VBScript has been installed by default in every desktop release of Microsoft Windows since Windows 98.

CScript.exe is part of Windows Script Host. Windows Script Host is distributed and installed by default on Windows 98 and later versions of Windows. It is also installed if Internet Explorer 5 (or a later version) is installed.

phuclv
  • 30,396
  • 15
  • 136
  • 260
12

If you are open to using PowerShell, zip capabilities are available in .NET 2.0 (PowerShell is .NET). Here's an a example (source) credit to Mike Hodnick:

########################################################
# out-zip.ps1
#
# Usage:
#    To zip up some files:
#       ls c:\source\*.txt | out-zip c:\target\archive.zip $_
#
#    To zip up a folder:
#       gi c:\source | out-zip c:\target\archive.zip $_
########################################################

$path = $args[0] $files = $input

if (-not $path.EndsWith('.zip')) {$path += '.zip'}

if (-not (test-path $path)) { set-content $path ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18)) }

$ZipFile = (new-object -com shell.application).NameSpace($path) $files | foreach {$zipfile.CopyHere($_.fullname)}

phuclv
  • 30,396
  • 15
  • 136
  • 260
Beaner
  • 3,707
8

There is a single, simple cmd.exe command for this (through PowerShell v5.0+).

To zip:

powershell Compress-Archive -LiteralPath 'C:\mypath\testfile.txt' -DestinationPath "C:\mypath\Test.zip"

To unzip:

powershell Expand-Archive -LiteralPath "C:\mypath\Test.Zip" -DestinationPath "C:\mypath" -Force

Sources:

Special thanks to @Ramhound.

6

You can eliminate the risk of timing out during compression by polling for existence of the compression dialog window. This method also handles the user cancelling out of the compression window.

objShell.NameSpace(ZipFile).CopyHere(source)

' Wait for compression window to open set scriptShell = CreateObject("Wscript.Shell") Do While scriptShell.AppActivate("Compressing...") = FALSE
WScript.Sleep 500 ' Arbitrary polling delay Loop

' Wait for compression to complete before exiting script Do While scriptShell.AppActivate("Compressing...") = TRUE
WScript.Sleep 500 ' Arbitrary polling delay Loop

phuclv
  • 30,396
  • 15
  • 136
  • 260
5

If you are able to install the Resource Kit Tools, you will find a command line tool called COMPRESS that can create compressed archive files like zip.

Microsoft (R) File Compression Utility  Version 5.00.2134.1
Copyright (C) Microsoft Corp. 1990-1999.  All rights reserved.

Compresses one or more files.

COMPRESS [-r] [-d] [-z] Source Destination
COMPRESS -r [-d] [-z] Source [Destination]

  -r            Rename compressed files.
  -d            Update compressed files only if out of date.
  -zx           LZX compression.
  -z            MS-ZIP compression.
  -zq[n]        Quantum compression and optional level
                (in range 1-7, default is 4).
  Source        Source file specification.  Wildcards may be used.
  Destination   Destination file | path specification.
                Destination may be a directory.
                If Source is multiple files and -r is not specified,
                Destination must be a directory.
cowgod
  • 1,884
4

If on Windows 8 or Windows Server 2012 you'll have PowerShell and .NET 4.5, so you can do this:

zip.ps1 (usage: -directory <directory to zip up> -name <zip name>):

param (
    [string]$directory,
    [string]$name
)

Add-Type -Assembly System.IO.Compression.FileSystem
[System.IO.Compression.ZipFile]::CreateFromDirectory($directory, $name, [System.IO.Compression.CompressionLevel]::Optimal, $false)

zip.bat (if you need a helper to call PowerShell for you, the directory is first argument and the ZIP name second):

@Echo Off
powershell -ExecutionPolicy ByPass -Command "& '%~dpn0.ps1' -directory '%1' -name '%2'"
Hashbrown
  • 3,338
  • 4
  • 39
  • 51
3

This is a mutation of the accepted answer. I do a ton of automation tasks on up to thousands of files at a time, so I can't just sleep for 2 seconds and not care about it. I gleaned the workaround here, which is also similar to Jiří Kočara's answer here.

This will cause the destination folder to be pinged every 200 ms, which is approximately as fast as Microsoft says to check for file system updates.

Set parameters = WScript.Arguments
Set FS = CreateObject("Scripting.FileSystemObject")
SourceDir = FS.GetAbsolutePathName(parameters(0))
ZipFile = FS.GetAbsolutePathName(parameters(1))
CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)
Set shell = CreateObject("Shell.Application")
Set source_objects = shell.NameSpace(SourceDir).Items
Set ZipDest = shell.NameSpace(ZipFile)
Count=ZipDest.Items().Count
shell.NameSpace(ZipFile).CopyHere(source_objects)
Do While Count = ZipDest.Items().Count
    wScript.Sleep 200
Loop
phuclv
  • 30,396
  • 15
  • 136
  • 260
3
'Keep script waiting until compression is done
Do Until objShell.NameSpace( ZipFile ).Items.Count = objShell.NameSpace( InputFolder ).Items.Count
    WScript.Sleep 200
Loop
phuclv
  • 30,396
  • 15
  • 136
  • 260
2

Multiple files / directories with simplified code.

cscript zip.vbs target.zip sourceFile1 sourceDir2 ... sourceObjN

zip.vbs file

Set objArgs = WScript.Arguments
ZipFile = objArgs(0)

' Create empty ZIP file and open for adding CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar) Set zip = CreateObject("Shell.Application").NameSpace(ZipFile)

' Add all files/directories to the .zip file For i = 1 To objArgs.count-1 zip.CopyHere(objArgs(i)) WScript.Sleep 10000 'REQUIRED!! (Depending on file/dir size) Next

phuclv
  • 30,396
  • 15
  • 136
  • 260
Olc
  • 29
1

Here's my attempt to summarize built-in capabilities in Windows for compression and uncompression - How can I compress (/ zip ) and uncompress (/ unzip ) files and folders with batch file without using any external tools? - with a few given solutions that should work on almost every Windows machine.

As regards to the shell.application and WSH, I preferred the JScript one as it allows a hybrid batch/JScript file (with .bat extension) that does not require temporary files. I've put unzip and zip capabilities in one file plus a few more features.

npocmaka
  • 1,313