As npocmaka said, Windows can't add a single empty folder to a zip file either through scripting or drag-and-dropping.
But you've inspired me. I decided to write a zip utility in JScript, just to see whether I could. To address your current problem, I added a check for empty folders. If an empty folder is encountered, this script will create a new child folder within called "(empty)". It was either that, add a 0-byte file, or throw an error and skip adding the folder.
Anyway, if you'd like to try it, save this script with a .bat extension and run it. Granted, it's not as simple as your VBscript, but it's got better logging, error handling, and timing; and it can zip individual files as well as folders.
@if (@a==@b) @end /* JScript ignores this multiline comment
:: zip.bat file/folder1 [file/folder2 [file/folder3 etc...]] [-o outfile.zip]
:: creates a zip file
@echo off
setlocal enabledelayedexpansion
if "%~1"=="" (
echo Usage: %~nx0 [-o outfile.zip] "file1 or folder1" ["file2 or folder2"] etc.
echo If -o is not used, the zip file is named based on the first infile.
goto :EOF
)
:: convert wildcards to individual filenames
for %%I in (%*) do (
echo(%%I | findstr "[\*\?]" >NUL && (
for /f "tokens=*" %%x in ('dir /b %%I') do set "args=!args! "%%~fx""
) || set "args=!args! "%%~I""
)
if "!args!" equ "" (
echo(%* does not exist.
goto :EOF
)
cscript /nologo /e:Jscript "%~f0" !args!
goto :EOF
:: end of batch portion / begin JScript portion */
var files = [], outfile,
fso = new ActiveXObject("scripting.filesystemobject"),
shl = new ActiveXObject("shell.application");
function chr(n) { return String.fromCharCode(n); }
for (var i=0; i<WSH.Arguments.length; i++) {
if (WSH.Arguments(i).toLowerCase() == '-o') outfile = WSH.Arguments(++i);
else files.push(WSH.Arguments(i));
}
if (!outfile) try { outfile = files[0].split(/[\/\\]/)[0] + '.zip'; }
catch(e) { outfile = 'archive.zip'; } // Probably never see this, but just in case.
WSH.Echo('Creating ' + outfile);
var zip = fso.CreateTextFile(outfile);
zip.Write("PK" + chr(5) + chr(6));
for (var i=18; i>0; i--) zip.Write(chr(0));
zip.Close()
zip = shl.NameSpace(fso.GetFile(outfile).Path);
for (var i=0; i<files.length; i++) {
try {
if (fso.FileExists(files[i])) {
var file = fso.GetFile(files[i]);
} else if (fso.FolderExists(files[i])) {
var file = fso.GetFolder(files[i]);
if (!shl.NameSpace(file.Path).Items().Count) {
// Windows can't add an empty folder to a zip file, but
// it *can* add a folder that contains an empty folder.
shl.NameSpace(file.Path).NewFolder('(empty)');
}
} else {
throw "Unable to locate " + files[i];
}
var folder = shl.NameSpace(file.ParentFolder + '\\'),
zipThis = folder.ParseName(fso.GetFileName(files[i]));
}
catch(e) {
var output = 'Skipping ' + files[i] + ': ';
output += (typeof e === 'string') ? e : (
e.description ? e.description : 'error ' + e.number + ' (unspecified error)'
);
WSH.Echo(output);
files.splice(i--,1);
continue;
}
WSH.StdOut.Write('Compressing ' + fso.GetFileName(file) + '... ');
zip.CopyHere(zipThis);
while (zip.Items().Count <= i) {
WSH.Sleep(50);
}
WSH.Echo('Done. (' + zip.Items().Count + ' of ' + files.length + ')');
}
if (!zip.Items().Count) {
fso.DeleteFile(fso.GetFile(outfile));
WSH.Echo('Zip file is empty. Deleting.');
}
The advantage of using JScript over VBScript here is that there's no need to echo out to _zipIt.vbs. JScript affords the ability to be evaluated inline as a hybrid of a batch script. Your vbscript you plundered has another issue, in that it arbitrarily calls WScript.Sleep 2000, regardless of how much time is needed to complete the copy. If you're copying large files, 2 seconds might not be enough time. And it's wasteful if you're copying something small.