Run Automator .workflow file from AppleScript

I wondering if it’s possible to run an Automator workflow (.workflow file, not .app) from a script. I saw this below a while ago but I can’t get it to work.

tell application “Automator Launcher” to open “Macintosh HD:Users:userName:Desktop:foo.workflow”

If not I’ll just run a workflow saved an as application, but I would prefer to be able to run .workflow files if possible.

You can use the built-in automator command line utility to fire of Otto’s workflows from within AppleScript using the do shell script command:


set workflowpath to "Macintosh HD:Users:martin:Desktop:Example.workflow"
set qtdworkflowpath to quoted form of (Posix path of workflowpath)
set command to "/usr/bin/automator " & qtdworkflowpath
set output to do shell script command

Type man automator into an open Terminal window to learn more. Or visit Apple’s own website.

Brilliant, thanks a lot! :smiley:

Sorry forgot, one last question. How would I send the selected file (e.g. on the Desktop, in a Finder window etc.) to that workflow? (So that the Automator workflow would act on the selected file).

In the past I’ve done it with a workflow saved as an application like this:

tell application "Finder" to open the selection using "Macintosh HD:Users:Jono:Documents:File A.app"

The easiest way is to add a get selection to the workflow.

You can pass input parameters with the -i flag*

An example: Let’s say your workflow starts with the «Get Folder Contents» action. Then you could pass the initial folder path with code like follows:


set qtdstartpath to quoted form of (Posix path of (path to desktop))
set workflowpath to "Macintosh HD:Users:martin:Desktop:Example.workflow"
set qtdworkflowpath to quoted form of (Posix path of workflowpath)
set command to "/usr/bin/automator -i " & qtdstartpath & " " & qtdworkflowpath
set output to do shell script command

  • Mac OS X 10.5

Thanks a lot for this, I really apreciate it (both of you).

I’ll mainly start the workflows with ‘Get Selected Finder Items’ to select 1 or more files. Would the script be different for this, or same as get a folder’s contents?

But I do also have some uses where I’d like to grab a folder’s contents, so the script above will also come in very handy.

Thanks again.

I was going to post similar also, :rolleyes: but found it more bother and slower than just adding, the workflow action.
mainly because if you have more than one item selected, you have to play with a list, and add spaces …

tell application "Finder" to set Sel to (selection) as alias list
repeat with i from 1 to number of items in Sel
	set item i of Sel to (quoted form of (POSIX path of item i of Sel)) & space
	
end repeat

set workflowpath to "Macintosh HD:Users:martin:Desktop:Example.workflow"
set qtdworkflowpath to quoted form of (POSIX path of workflowpath)
set command to "/usr/bin/automator -i " & (items of Sel as string) & qtdworkflowpath
set output to do shell script command

If you want to choose files/folders or both, and or folder content.

You can add Ask for finder items. And Get folder contents.

Brilliant, thanks a lot! :smiley:

I’m having a little trouble with this. I’ve set up a workflow that converts image files to a PDF. I’ve tested it as both a Service and a Workflow. When it’s a service I just have to select the images in the Finder, right click and choose the workflow to convert them all into a single PDF. It works perfectly.

I want to put this into an AppleScript so I tried the following by adapting the last code from mark hunte above:


set InputFolder to alias "Macintosh HD:Users:david.morgan:Desktop:Temp:Test JPEGs:"
tell application "Finder" to set FileList to every file in folder InputFolder as alias list
repeat with i from 1 to count FileList
		set item i of FileList to (quoted form of (POSIX path of item i of FileList)) & space
end repeat
--
set workflowpath to "Macintosh HD:Users:david.morgan:Desktop:Make_PDFs.workflow"
set qtdworkflowpath to quoted form of (POSIX path of workflowpath)
set command to "/usr/bin/automator -i " & (items of FileList as string) & qtdworkflowpath
set output to do shell script command

but it only ever makes the first image into a single page PDF, seemingly ignoring the other images in the folder. I looked up the manual for automator in Terminal and it says to use the newline character (\n) as the delimiter for multiple strings. I tried this too but with even less success.

Any suggestions?

Model: iMac
Browser: Chrome
Operating System: Mac OS X (10.10)

You could skip Automator altogether:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
use framework "AppKit" -- for NSImage
use framework "Quartz" -- required for PDF stuff

set inFiles to (choose file of type {"public.image", "com.adobe.pdf"} with prompt "Choose your  files:" with multiple selections allowed)
set destPosixPath to POSIX path of (choose file name default name "Combined.pdf" with prompt "Save new PDF to:")
my combineFiles:inFiles savingToPDF:destPosixPath

on combineFiles:inFiles savingToPDF:destPosixPath
	--  make URL of the first file
	set inNSURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of item 1 of inFiles)
	-- make PDF document from the URL
	if (inNSURL's pathExtension()'s isEqualToString:"pdf") as boolean then
		set theDoc to current application's PDFDocument's alloc()'s initWithURL:inNSURL
	else
		set theDoc to my pdfDocFromImageURL:inNSURL
	end if
	-- loop through the rest
	set oldDocCount to theDoc's pageCount()
	set inFiles to rest of inFiles
	repeat with aFile in inFiles
		--  make URL of the next PDF
		set inNSURL to (current application's |NSURL|'s fileURLWithPath:(POSIX path of aFile))
		-- make PDF document from the URL
		if (inNSURL's pathExtension()'s isEqualToString:"pdf") as boolean then
			set newDoc to (current application's PDFDocument's alloc()'s initWithURL:inNSURL)
		else
			set newDoc to (my pdfDocFromImageURL:inNSURL)
		end if
		-- loop through, moving pages
		set newDocCount to newDoc's pageCount()
		repeat with i from 1 to newDocCount
			-- get page of  PDF
			set thePDFPage to (newDoc's pageAtIndex:(i - 1)) -- zero-based indexes
			-- insert the page into main PDF
			(theDoc's insertPage:thePDFPage atIndex:oldDocCount)
			set oldDocCount to oldDocCount + 1
		end repeat
	end repeat
	set outNSURL to current application's |NSURL|'s fileURLWithPath:destPosixPath
	-- save the main PDF
	(theDoc's writeToURL:outNSURL)
end combineFiles:savingToPDF:

on pdfDocFromImageURL:inNSURL
	set theImage to current application's NSImage's alloc()'s initWithContentsOfURL:inNSURL
	set theSize to theImage's |size|()
	set theRect to {{0, 0}, theSize}
	set theImageView to current application's NSImageView's alloc()'s initWithFrame:theRect
	theImageView's setImage:theImage
	set theData to theImageView's dataWithPDFInsideRect:theRect
	return current application's PDFDocument's alloc()'s initWithData:theData
end pdfDocFromImageURL:

Rescued me again Shane. Let me guess, that’s something you prepared earlier?
I knew there must be a way to do this using Obj C but would never have worked it out. There sure is a lot going on in that code. Works blazingly fast though, thanks very much!

Perhaps academic now, but the trick with the automator shell script appears to be to use the quoted form of the entire linefeed-delimited input rather than quoting the paths individually:


set InputFolder to ((path to desktop as text) & "Temp:Test JPEGs:")
tell application "Finder" to set FileList to every file in folder InputFolder as alias list

repeat with i from 1 to count FileList
	set item i of FileList to POSIX path of item i of FileList -- Not quoted forms here.
end repeat
-- Coerce the list to a single, linefeed-delimited text.
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to linefeed
set input to FileList as text
set AppleScript's text item delimiters to astid
-- Get the quoted form of the result.
set qtinput to quoted form of input
--
set workflowpath to (path to desktop as text) & "Make_PDFs.workflow"
set qtdworkflowpath to quoted form of (POSIX path of workflowpath)
set command to "/usr/bin/automator -i " & qtinput & space & qtdworkflowpath
set output to do shell script command

That works a treat too. Thanks Nigel, I was messing around with Terminal but didn’t think of putting the whole lot in single quotes.

You can also run a workflow like this:

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

set InputFolder to ((path to desktop as text) & "Temp:Test JPEGs:")
tell application "Finder" to set FileList to every file in folder InputFolder as alias list

repeat with i from 1 to count FileList
	set item i of FileList to POSIX path of item i of FileList 
end repeat
--
set workflowPath to POSIX path of ((path to desktop as text) & "Make_PDFs.workflow")
set workflowURL to current application's |NSURL|'s fileURLWithPath:workflowPath
set {theResult, theError} to current application's AMWorkflow's runWorkflowAtURL:workflowURL withInput:FileList |error|:(reference)
if theError is not missing value then error (theError's localizedDescription() as text)

Hi Shane.

  1. This script’s problematic on my El Capitan machine for some reason. The PDF is invariably correctly created, but the runWorkflowAtURL: method usually doesn’t return. Script Debugger goes into an eternal beachball state; Script Editor reports after a quarter of a minute or so that the operation couldn’t be completed. Occasionally, though, the method does complete, usually (but not always) when I feed FileList in directly as a list of aliases instead of POSIX paths or NSURLs. :confused:

  2. By my reading of the method’s documentation, the result will be nil either if an error occurs or if there’s no output from the workflow. If I’ve got that right, the last line of the script (assuming it gets that far!) should be:

if theError ≠ missing value then error (theError's localizedDescription() as text)

Do you have Show this action. turned off and Replace Existing Files on?

Yes, you’re right: “The error argument must be examined to determine which scenario occurred.” Which flies in the face of Apple’s advice on how to deal with NSErrors.

Yep. And it actually does what it’s supposed to. It just doesn’t hand back to the script afterwards.

Prompted by the fact that the effect’s slightly different depending on whether I run the script in Script Debugger (beachball) or Script Editor (eventual “operation couldn’t be completed” message), I’ve just tried saving the script as an application with an extra line to say that it’s done and running it under its own steam. It works perfectly well in this form and announces “Finished” almost immediately. There must be something about running it in an editor which my system doesn’t like.

Does it make any difference if you only have a couple of small files to process?

I’ve tried fewer JPEGs, smaller JPEGs, different JPEGs, and JPEGs all with the same orientation. I’ve also tried making all the script variables ” and even the script itself ” non-persistent. The results are always the same:

Script as application ” no problem.
Script in Script Debugger ” workflow works, SD beachballs.
Script in Script Editor ” workflow works, SE displays error message after several seconds: error “The operation couldn’t be completed. (com.apple.Automator error 0.)” number -2700 from «script» to item. In this case, if the error reporting line at the end of the script is left out, SE’s result pane eventually shows {missing value, «class ocid» id «data optr0000000000F1D1338D7F0000»}, so SE does get a reply from the workflow, even if it’s just the error.

I’ve also added a Run AppleScript action to the end of the workflow to announce when the New PDF from Images action has finished and how many items it’s passed on. The announcement always happens, however the script’s run. SD’s timer stops at the end of the announcement, but its status bar still shows “Running” and eventually the beachball appears.

PS. In ASObjC Explorer 4, the behaviour’s the same as in Script Editor. However, with the “Run in foreground” box checked, everything works perfectly! Could be a thread problem.