Put a password on zipped files, without using the command line

I decided to scratch that itch in the last few days.

Basically I’m trying to reproduce the behavior of Finder when you select files to zip, but this time with a password added to the resulting archive.


Nice site. Thanks!!

I have a few compressing routines myself, but with 7z, as it has more compressing power and tar just for storing.

Hi. Minimally, it’s user-unfriendly to post a link to another site where code may reside, rather than to wrap it in this site’s own tags, and it may even be a security risk.

Your rationale for tracking the shortest directory appears to relate to the CD command, from my skimming of your code; that step can be avoided. Here is an alternative:

set folderTarget to (choose folder)
tell application "Finder" to set {isName, folderAncestor, wordpass} to {folderTarget's name, (folderTarget's container as text)'s POSIX path, (display dialog "Input the password:" default answer "whatever")'s text returned}
do shell script "zip -rj " & (folderAncestor & isName & ".zip")'s quoted form & space & folderTarget's POSIX path's quoted form & space & "-P " & wordpass's quoted form

Thank you for the comment. I’m trying to stick to what macOS offers out of the box, just in case people find the script useful and want to try it on their machine.

Thank you for the comment.

I’m not aware that linking to a site where non executable code is hosted can be a security risk. Also, that blog is where I write, and I don’t see a reason why I’d need to copy such contents to all the places I visit.

No, the rationale for the shortest common directory is to find the place where to put the archive when multiple files are selected. I wrote about that in the introductory part to the code.

If you meant to say that using the -j option with zip would remove useless folders, which is the only fundamental difference between my code and yours, you did not have to obfuscate that information in AS code. Also, your code may be an alternative for zipping a single file, but it does not reduce complexity by a significant amount. When I work on the command line, I usually prefer to work from the appropriate working directory, that reduces the chances of silly mistakes.

Also, as written above, your code is not an alternative for zipping multiple files situated at different locations on various folder hierarchies. It is totally possible that there is a more idiosyncratic way to do that in AS, and I certainly do not pretend that what I wrote was 100% satisfactory, but that part is the core of the code I wrote, not zipping a single file, which can be completed easily enough.

If you have suggestions to reduce the complexity of that part of the code while sticking to my requirements (as close as possible to Finder’s own behavior when you select "Compress … items) I’d sincerely be happy to read them.

A website is executable code and can contain trackers or other nuisance scripts in addition to the visible contents. Placing code within tags on the appropriate MacScripter forum is safer and easier for the users of this site to evaluate and run.

Whether there are single or multiple files, the same shell command is issued. Discarding paths impacts overall complexity and code length; Finder is only capable of selections from within one folder of any given window, and only the active window’s selection is compressed, so you should need to only sample one directory. I think this replicates the general behavior:

tell application "Finder" to set {FinderRefs, wordpass} to {selection as alias list, (display dialog "Input the password:" default answer "whatever")'s text returned}
set PosixList to {}
repeat with aFile in FinderRefs
	set PosixList's end to aFile's POSIX path's quoted form & space
end repeat
set commonPath to do shell script "dirname " & PosixList's item 1
do shell script "zip -rj " & (commonPath & "/zip-a-dee-doo-dah")'s quoted form & space & PosixList & space & "-P " & wordpass's quoted form

Not so. Show a window in list view with contained folders expanded, and start command-clicking.

Now try doing that and running the OP’s script – the resulting archive is quite different to that produced by your code.

If you’re arguing that the whole internet is broken, that’s fair. But this is hardly the right forum to complain about that. Now if it is a policy of Macscripter to forbid posting external links to the forum, I’m sorry if I missed that.

When I wrote on the blog that it took me 3 days to write the thing, it was not only because I am not a native AppleScript speaker, but it was also because Finder shows plenty of interesting behaviors that I tried to emulate, because I think what Finder does is convenient and all the other scripted zipping solutions I found on the web did not try to go that far and thus were less convenient.

When I talk about reducing complexity I mean using more idiosyncratic forms that I have missed because I don’t practice AppleScript as much as I’d want to.

I’m thinking in particular about the 2 repeat loops and the equality condition that create the shortest common path. I’d like to find a more elegant way to do that. I thought of doing something like applying AND to all the columns of a given matrix but I had no idea hw to implement that in AppleScript. If you have suggestions for that please go ahead.

I just tried your code and it does something very differently from what mine does.
For ex, in list view, if I select the following paths on my machine from the Desktop window:

/Users/suzume/Desktop/test ocr2/Test OCR_1.rtf
/Users/suzume/Desktop/Test OCR_1/img7.png
/Users/suzume/Desktop/test/Simple Tags/tm/tmx2source/FR_FR.po
/Users/suzume/Desktop/test/Simple Tags/omegat/project_save.tmx.201707032318.bak

I get an archive here:
/Users/suzume/Desktop/test ocr2/zip-a-dee-doo-dah.zip

When I do the same with the Compress … in Finder, the archive is put here:

And it is where my script puts it too. Because Desktop is the shortest common path between all the selected items.

perhaps something like:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use scripting additions

tell application "Finder"
	set mySelection to selection as alias list
end tell

set firstPath to POSIX path of item 1 of mySelection
set commonPrefix to current application's NSString's stringWithString:firstPath
repeat with aFile in rest of mySelection
	set aPath to POSIX path of aFile
	set commonPrefix to (commonPrefix's commonPrefixWithString:aPath options:0)
end repeat
set commonPrefix to commonPrefix as text

Not much shorter, but perhaps a bit more self-explanatory.

Also, you have a couple of lines in there that do nothing (“set archiveFile to…” and “select archiveFile”).

Thank you Shane :slight_smile:

I was not aware of “rest of”, although I’m pretty sure I checked the reference for efficiently working on lists… :frowning: Thank you !

Too bad commonPrefixWithString does not seem to exist in AppleScript. I checked the reference in Xcode and the info regarding “options: 0” points to an Apple site that is currently not available.

Yes… Traces of previous versions of the code… For code this size it should be easy to notice such lines, but when you have much bigger files, is there a way to automatically find them ?

The only options that can be used here are NSCaseInsensitiveSearch and NSLiteralSearch, neither of which should make any difference here here.

Posting the code somewhere public often works :wink:

Ooops, my earlier reply was mistaken. Those 2 lines actually implement the equivalent of Finder opening a new window on the folder where the archive was created and selecting it, but you can only see that in List display mode.

I just tested on my machine and it worked for both single file and multiple file compression. But indeed, when you’re not in List mode, Finder doesn’t do anything special, it just selects the file, and that corresponds to the situation that Mark was describing.

Ah, I just realised they’re in one huge Finder tell block. That’s not a good idea: just put the stuff addressed to the Finder in its tell block, not the rest of the code.

Hey guys,

My window behavior didn’t jibe with your statements in posts #7 and #8, then I realized that not only must a window be in list view but the arrange option has to be set to none for expansion triangles to appear. Given the fact that a selection is being used, Finder can efficiently locate the common path by index. Try this:

tell application "Finder" to set {FinderRefs, commonDir} to {selection as alias list, (get selection)'s item -1's container as alias}
set PosixList to {}
repeat with aFile in FinderRefs
	set PosixList's end to aFile's POSIX path's quoted form & space
end repeat
do shell script "zip -rj " & (commonDir's POSIX path & "/zip-a-dee-doo-dah")'s quoted form & space & PosixList


I’m not sure you can rely on the order selected items are passed back. I know in the past I’ve seen all sorts of oddities – sometimes it relates to selection order, sometimes not.

In any event, the problem with using -j is that it completely flattens the hierarchy. The point of the script is to faithfully maintain the hierarchy in the archive, but anchored to the longest common path so the archive doesn’t unpack as Users//blah/blah/…

Marc & Shane,

Thank you very much for the discussion. It’s amazing to see how such a common piece of software like Finder can be subject to various sorts of uses that create totally different perceptions and expectations of how the software works.

I’m glad that the time I spent on this script resulted in something that seems to have little coding issues and that in the end generally replicates Finder’s behavior.

The main problem I had this time was understand what “references” were and how to handle them. I know that I’ve not fully understood what they are but I also know that all sorts of errors I did not understand before can be explained by me trying to do things to objects that are or are not references. At least I am a bit less lost now.