Can you zip a file from the command prompt using ONLY Windows' built-in capability to zip files?

113

47

I have a batch file that outputs a text file. I thought it would be nice if I could zip it up 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, etc. This needs to use Windows' now-built-in capability to zip files.

Aaron Bush

Posted 2010-02-19T19:46:23.680

Reputation: 1 273

1can you utilize Powershell or WSH scripting? that might be the only way to use Windows' builtin zip handling from the commandline. otherwise, as Molly points out, you need a 3rd-party tool. – quack quixote – 2010-02-19T19:59:27.190

1so you send someone a batch file and you can not send him some tiny statically linked gzip.exe? – akira – 2010-02-19T22:16:31.360

The OP's question is an excellent one (@quackquixote 's strange accusation notwithstanding). Since Windows does provide this as a single click under SendTo, there ought to be a command usable in a BAT file. So it's a good question even if the answer is No and one has to (ridiculously) resort to using a third-party tool that may or may not be equivalent. – Jon Coombs – 2014-12-24T00:33:05.703

This is link by Tomas has a well written script to zip contents of a folder.

To make it work just copy the script into a batch file and execute it by specifying the folder to be zipped(source).

No need to mention destination directory as it is defaulted in the script to Desktop ("%USERPROFILE%\Desktop")

– Abhijeet – 2016-01-11T02:46:23.023

3The simpliest would be, in a cmd prompt : powershell.exe Compress-Archive file-to-zip.txt zippedfile.zip (it works with folder too) – ThomasGuenet – 2017-09-05T08:33:05.530

Answers

86

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.

Peter Mortensen

Posted 2010-02-19T19:46:23.680

Reputation: 10 992

Why do we have to use a temp folder TEMPDIR? I think your intention is to wrap the file FILETOZIP by a folder right? – Nam G VU – 2014-10-15T02:11:17.943

3@quack I was holding out in the hope of some obscure command that I didn't know about. I can see how you might find that a difficult requirement if one doesn't exist, didn't mean to put anybody out. – Aaron Bush – 2010-03-02T13:56:36.587

@Peter Mortensen, I know this is an old thread, and this is almost what I'm looking for. Is there an option to compress one big file into smaller chunks? – JohnG – 2016-05-18T16:21:35.350

can this be customized to receive parameters from node.js execute command, name of the source folder and destination of the zip file – user2727195 – 2016-07-12T19:13:55.110

@PeterMortensen: It may or may not be interesting to see how much this is simplified with Powershell. Here is a 5 line example, but there also exists a write-zip cmdlet that can be downloaded from the Pscx.

– Tamara Wijsman – 2011-11-29T13:54:15.537

I used the zip.exe and cywin1.dll (3mb) to satisfy the ZIP and usage is one line... from the zip itself of using some batch code. I know can use a php bancompile'd with argv and pass a file to it. Sounds cool. "A zip from windows command line" is an old science fiction movie, right? – m3nda – 2013-12-10T06:59:02.020

40

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.

Peter Mortensen

Posted 2010-02-19T19:46:23.680

Reputation: 10 992

The zip files this creates for me are showing up as corrupted/incomplete. – Bobson – 2014-08-22T19:29:51.863

1+1 Good solution that will "Just Run", but I choose BAT for several other reasons not listed. So I would prefer a BAT solution. – Aaron Bush – 2010-02-22T13:30:44.357

4@Aaron Bush: this script and Beaner's both provide a command that zips a file on the commandline, using windows builtin functions, as requested. you can add that command to a batchfile like any other. – quack quixote – 2010-02-22T23:24:20.483

Note you can use CreateObject("Scripting.FileSystemObject").GetAbsolutePathName(objArgs(0)) to get absolute path names – Thom Nichols – 2015-04-29T19:12:28.283

Why is wScript.Sleep 2000 required? – kayleeFrye_onDeck – 2017-05-25T21:50:24.683

For those who have problem (randomly fail, corrupted zip...) just increase the 2 seconds time-out to more seconds!! – Patrick from NDepend team – 2017-10-13T06:54:21.887

This even works when run from Git Bash which for some reason has unzip but not zip. For example in a whatever.sh script I can run CScript zip.vbs /c/Temp/${WHATEVER} ${WHATEVER}.zip – simbo1905 – 2019-08-21T07:36:25.040

Note that the paths passed in have to be absolute, not relative. I had to also use the techniques in the answer here: http://stackoverflow.com/q/1645843/99640

– Chuck Wilbur – 2012-06-27T21:08:39.383

Paths have to be absolute and it seems to randomly fail :( – kixorz – 2014-02-13T20:33:48.687

This should be selected as the answer. – The Duke Of Marshall שלום – 2014-03-14T17:48:25.893

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)}

Beaner

Posted 2010-02-19T19:46:23.680

Reputation: 3 193

2The .NET System.IO.Compression.ZipFile class was added in version 4.5 . – Concrete Gannet – 2014-11-24T08:00:36.277

This is basically the same thing as the CScript code in other answers. No .NET features are used (and .NET doesn't have ZIP support anyway). I suspect this might also be sensitive to the timing issue. – Robert Schmidt – 2014-02-25T08:14:14.353

7

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

George Yockey

Posted 2010-02-19T19:46:23.680

Reputation: 79

1+1. Those code monkey-style ".Sleep(whatever)" make me sick. – ivan_pozdeev – 2013-06-25T14:30:54.623

2If I am running a vbs with the above logic for waiting, how will this be handled if being launched via a scheduled task (where no user is physically logged in.) – Wes – 2013-06-27T22:05:48.730

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

Posted 2010-02-19T19:46:23.680

Reputation: 1 816

3+1 Doesn't really solve things, but still good to know about. – Aaron Bush – 2010-02-22T13:28:46.917

3

'Keep script waiting until compression is done
Do Until objShell.NameSpace( ZipFile ).Items.Count = objShell.NameSpace( InputFolder ).Items.Count
    WScript.Sleep 200
Loop

Jiří Kočara

Posted 2010-02-19T19:46:23.680

Reputation: 39

For some reason this never increments, if I print objShell.NameSpace( ZipFile ).Items.Count inside the loop, it's always 0 even though the zip file is created and it has the expected contents inside... – Thom Nichols – 2015-04-27T20:20:10.837

exactly what i was looking for.. but it does give me an error "missing on empty Zip file" – Sonic Soul – 2014-04-03T21:25:46.037

2

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 200ms, which is approximately as fast as Microsoft says to check for FS 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

kayleeFrye_onDeck

Posted 2010-02-19T19:46:23.680

Reputation: 183

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

Olc

Posted 2010-02-19T19:46:23.680

Reputation: 29

1

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

Posted 2010-02-19T19:46:23.680

Reputation: 1 720

1

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

tar.exe -xf archive.zip

or to create archive

tar.exe -cf Test.zip Test

venimus

Posted 2010-02-19T19:46:23.680

Reputation: 382

1

Here'a my attempt to summarize built-in capabilities windows for compression and uncompression - https://stackoverflow.com/questions/28043589/how-can-i-compres-zip-and-uncopress-unzip-files-and-folders-with-batch-f

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 as it allows a hybrid batch/jscript file (with .bat extension) that not require temp files.I've put unzip and zip capabilities in one file plus a few more features.

npocmaka

Posted 2010-02-19T19:46:23.680

Reputation: 887

-4

The Windows command line now provides the compact command which, as far as I can tell, is native to Windows. That should meet the requirements requested unless I missed something.

user228211

Posted 2010-02-19T19:46:23.680

Reputation: 13

@user228211 your answer is excellent fit for this question "use windows built-in zip capability". It should be one of the top answers due to simplicity and direct match to questions. Not sure why people are downvoting???? – LMSingh – 2020-02-28T22:31:26.880

9compact existed since XP and is a tool to manage NTFS compression – Der Hochstapler – 2013-05-31T20:06:30.383