Monthly Archives: September 2018

Mojave: not authorized to send Apple events

If you’re suffering from error messages like the one above after upgrading to Mojave, welcome to macOS’s new “User Data Protections”. In this post we’ll explain what they are and how to deal with them.

That error’s produced when the app your script is targeting (in this example, System Events) has been denied access to one of the areas now protected in Mojave.

Here’s the list of places which are no longer accessible programmatically without user approval on 10.14:

If the app you’re targeting in your script – or the script runner itself – is trying to access any of those 12 locations, you’ll likely either get the error shown at the top of this post, or some other failure. 

The official way of dealing with this is to add the application to System Preferences’ new ‘Full Disk Access’ section in the Privacy pane:

At least that’s the theory, but you might find that you’ve tried that and things are still not working. If that happens, you can “start over from scratch” by resetting the access permissions to default. 

In Terminal, try 

tccutil reset AppleEvents; tccutil reset SystemPolicyAllFiles

After you’ve done that, the next time you run that script you should get an authorization dialog like this: 

Alternatively, just go right ahead and add the app with the ‘+’ button in System Preferences.

Enjoy the resumption of normal service 🙂

hello, applescript 3: (don’t?) tell me to run

Continuing where we left off at the end of User In, User Out, let’s build on our knowledge of getting user input and using conditionals.


Script 7
In this script, we’re going to query the user for some information, and if that information meets a certain test, we’ll give the user one answer, if it doesn’t we’ll give them another. Kind of like a mini-quiz game program. There’s lots of new stuff in this script, but don’t be put off. Just bang it out on the keyboad, fix any typos if it won’t compile, and run it. Run it at least three times choosing a different button each time. We’ll go through it line by line after you’ve had a play around with it.





Line 1 assigns a string literal (the lovely “Loser”) to a variable, theReply. We’re doing two things here. We’re first declaring a variable that we’ll want to use later in the script, and we’re also initialising it with a default value. “Loser” is one of two possible values we’ll want this variable to have later, so we’ll set this as the default now, which means the variable will always have this value when we use it unless we change it later in the script.

Most of Line 2 should be familiar to you now, except that we’ve added a third button and a default value for the answer. We’ve also added a default button, in this case 3. To understand what the default button parameter does run the script with value 1, and then again with value 2.

As you will notice, the number refers to one of the buttons defined in the buttons list, where 1 is the first item in the list and the left most button, and 3 is the last item in the list and the right most button. The parameter determines which button has focus (and therefore responds to the return key on the keyboard).


If you’ve already tried experimenting with 4 buttons, you’ll see that the compiler complains that a maximum of 3 buttons is allowed. That’s not strictly true, but we’ll save that trick for later in the series.

Note: Lists in AppleScript, unlike most other modern programming languages, are not zero-indexed. The first item is item 1, not item 0 as it would be in Python, C, Swift and so on.

If you prefer you can also refer to buttons by their name instead of their index. This helps improve readability of your code and makes it clearer which button was intended as the default. To refer to the button by name, you would write the parameter like this:

default button "Sure?"

Line 3 should be familiar to you, but refer back to Script 6 in the previous post if you need a reminder.

Line 4 begins an if statement block that contains another if statement block (again, see Script 6), but there’s also something new here: the else condition. This says that if our condition in Line 4 isn’t met, do whatever’s in the else block starting at Line 10.

If the condition in Line 4 is met, however, then Line 6 offers a further condition: if the user typed in “Phil”, then Line 7 says change the value of the variable theReply from “Loser” to “Winner”. Note, particularly, that if this condition is not met, then the value of theReply will be “Loser” when it’s called later in the script.

Line 8 ends the inner if statement block.

Line 9 now says: display the dialog to the user, showing them the value of whatever theReply is currently set to (either “Winner” or the default “Loser”). Note that the same value is used to set the title.

Line 10 starts the else block. This will be triggered if the user doesn’t choose either “Cancel” – which would end the script – or “Sure?” – which would trigger the first condition – when Line 2 is executed.

We don’t need to put in a specific test for “Cancel” because “Cancel” will automatically end the script with error -128. However, as we’ll see later in the series, sometimes it can be useful to catch “Cancel” in the if block too, in order to execute certain commands before the script quits.

Line 11 may look a bit mysterious; this is your first introduction to AppleScript’s most pervasive control statement. tell is how you send a command to a particular object in AppleScript. If you’ve ever done any Object-oriented programming, another way of expressing the same idea is to say tell allows you to target a message toward an object. In this case the object is me — a built-in AppleScript keyword that refers to the script itself. So,

tell me to run

says “send the run message to the script”.

There’s an easy (and inaccurate) way to understand what that means, and a hard (and accurate) way. For now, we’re going to go easy so that the learning curve doesn’t get too steep. In this context, we will say that run means “go back to Line 1 and begin execution of the script again”.

Every time you choose “Try Again”, the script goes back to Line 1 and repeats itself until you choose one of the other answers.


Where we are: so far!
In this post, we’ve been introduced to AppleScript’s list class, consolidated our knowledge of display dialogs and if statements, and had our first taste of tell, me, and run. These concepts will require more elucidation and, most importantly, more practice, all of which are coming up!

In the next post hello applescript 4: shelling out, we’ll work with these concepts some more and build on them to produce our first practical scripts. Be sure to follow Applehelpwriter to be notified when the post is published.

See you there! 🙂




For extra credit:

This week’s extras
1. Modify Script 7’s inner if statement so that if the text returned contains your name, theReply is “Winner”; if the text contains “Phil”, theReply is set to “Runner Up”. Any other name should produce the default reply “Loser”.

There are in fact two ways to solve this challenge, see if you can produce both. For help, look up else if in the Control Statements Reference section of the AppleScript documentation.



Solutions from last time
1. Use the hidden answer parameter:





2. In the second exercise, we posed a number of questions. The easiest way to find out about the parameters for a command is to use Script Debugger’s Dictionary viewer, which you can access by clicking on the Window menu (not, confusingly, the Dictionary menu!) and choosing ‘Dictionary’.


Also, don’t forget to use the AppleScript documentation, which I’ve linked to multiple times in this and earlier posts. It’s a great source of information, hampered somewhat by the lack of an effective search feature on Apple’s site. An older, pdf version of the doc which you can search can be downloaded by clicking this link, and is also available from here. Bear in mind, though, that Apple’s online docs contain some information that the older pdf doesn’t.

We’ll leave the other questions open for now, as they’ll be coming up in later posts!





hello, applescript 2: user in, user out

If you’re ready to learn AppleScript, this is the place to start! If you’re not sure yet whether AppleScript is for you, take a look at the intro to this series, What’s the Use. For those of you that are ready, let’s fire up Script Debugger and write our first script!


Script 1
OK, you want ‘hello, world’? Of course, you do!

Here it is, with a difference:





Type it in to the editor’s window, then run the script by clicking the Run button or hitting “Command-R” on the keyboard.




Wow. No “print” command for one, and an actual user interface. Cool!

If you don’t see a notification in the top right of your screen, you may need to adjust your Notification preferences.

What happens if you leave off the last quotation mark?

Try it and see:




This is called a compile time error, one of three kinds we’ll learn about (the others are run time and logic errors). When you run a script, the AppleScript compiler first checks it for syntax errors. If all is well, it turns your plain text into “pretty print” (we’ll talk about what the syntax colouring means later in the series); if not, your text isn’t compiled and you get an error message.

You can get a compiler check anytime without running the script by clicking either the button or using “Command-K” on the keyboard.

You’ll notice that when you have a compile time error in Script Debugger, you get a message and the error number in the bottom left corner (you won’t see the error number if you’re using Apple’s Script Editor). These can be useful, so much so that we’ll write a little script ourselves to tell us more about the error based on the error number we get in hello, applescript 4: shelling out.

For now, let’s take a look at the message.

“Expected string but found end of script.”

It may seem rather cryptic at first, but it can be translated simply enough. A string in AppleScript (and most other programming languages), is text placed between a pair of quotation marks. Anything between quotes will be treated as just a piece of ordinary text and not as part of the programming language. display notification isn’t a string in our script: it’s part of the programming language – specifically, a command to do something. “hello, world”, on the other hand, is a string: it’s just the ordinary text we want to display. The compiler says it “expected a string” because it found the first quote mark at the beginning of “hello, indicating the start of a string. It then went looking for the second one to mark the end of the string, but instead found…yes, you guessed it: the end of the script!


Script 2
Replace the missing quotation mark. We’ll come back to error messages shortly, but for now, let’s add our own title to the notification rather than having the default one:




Make sure those quotation marks are balanced!




Looking good!


Script 3
Notifications are useful when all we want to do is pass a simple message, but if you need users to make a choice or you need to provide a longer message, we should use a dialog.

Type in the script as you see it on the left in the image below.




Run it, and click the “OK” button when the dialog appears. Now look at the Results pane (right-hand panel in Script Debugger; bottom Accessory view in Script Editor).

That looks interesting! Let’s explore some more.


Script 4
Let’s add some bells and whistles:




Run the script.




Click either one of the buttons to end the script. Again, remove the quote mark after “world”, but this time don’t try to run the script. Just try to compile it. Remember, you can do that either by clicking the button in the toolbar or “Command-K” on the keyboard.

Notice this time we get a different error message and a different number, despite the fact that we seem to have errorred in exactly the same way and in exactly the same place as before:




Or did we? Look at it from the compiler’s point of view. Just as before, the compiler finds the first quote mark and continues looking. But this time it does find the second one! Only it’s not where it’s meant to be. Because we left off the quote mark after “world”, the compiler assumes that the quote mark that prefixes “Message is the closing quote mark for the opening one:




As a result, the term Message looks to the compiler like its supposed to be part of the programming language, as it follows the string “hello world with title ”. That sure is a valid string (you can put any text you like in your string, it doesn’t have to make sense), but what follows it is not a valid part of the programming language. You can learn more about identifiers here, but for now, just note that this error message has the form “this can’t go after that”, and is another clue that our quote marks are unbalanced.

What about the third quote mark? The compiler never sees it. The compiler reads from left to right, so after pairing the first two quote marks it throws the error and stops trying to read any further. If there are further errors in our script, we’ll never know till we fix (all) the preceding ones.

After you dismiss the error alert, the compiler is kind enough to highlight the this (“Message”) that can’t go after the that (“"“) in your script.

Errors -2740 and -2741 are common enough that whenever you see them, you now know what to check first: are my quotation marks balanced?

Let’s get back to our display dialog command. Are you wondering what happens if you use another number instead of 2 after with icon? I hope so!

Replace the missing quotation mark, and experiment by changing the number after with icon for all three values from 0 to 2.

Normally, you’ll use with icon 1, which will insert the icon of the executing program. In this case, that’s the icon for Script Debugger, but as you go through this series you’ll be learning how to execute your scripts in other ways, and it’s useful to have the icon of the executing program visible in the dialog box so that you know exactly where it’s coming from.

Our dialog box has some unnecessary cruft. We have an “OK” button and a “Cancel” button, but they appear to do the same thing; that is, they halt the script. But look a bit closer at the editor. Run the script again, twice, choosing the “Cancel” button first, and then the “OK” button on the second run.

When you choose “Cancel” there is no result, but there is an error message in the Events pane, specifically, error -128.




Errors, error messages and error numbers are powerful friends. We’ll see how we can harness errors like -128 later in the series.

When you run the script again and choose “OK”, however, there is a result. There are many result types, but in this case you get what is known as a record (similar to a Dictionary or key/value pair in other languages) in the Results view:

{button returned:"OK"}

The record contains a label (in this case, button returned, and a value (here, "OK"). This is important, as we’ll see in the following scripts.


Script 5
What if we want to get more than just an acknowledgement, but need some input from the user? Here’s one way:




Run the script, type in an answer, and hit “OK”. Take a look at the result:

{button returned:"OK", text returned:"Phil"}

It’s a record again, with the added pair “text returned” and the text that the user typed.

The default answer parameter is an empty string. What happens if you put some text between the quote marks and run the code?


Script 6
Let’s build on Script 5 and capture the answer that the user provides:




This script has a lot of new stuff going on. Let’s take it from Line 2 (refer back to Script 5 for line 1):


Line 2
This captures the result of the dialog in a variable called dialogAnswer. The result of the dialog isn’t the name you typed in, but the record of two labels with two values. In other words, the value of dialogAnswer is:

{button returned: "OK", text returned: "Phil"}

We could have called the variable (almost) anything we liked. I just chose dialogAnswer because it’s descriptive.

Descriptive names are useful because when I read back my script at some point in the future, it’ll be immediately obvious what this variable represents. However, I could have called it alpha, or just d or almost anything else. There are some reserved words in AppleScript that you can’t use, and you also can’t start variable names with a number or use certain special characters in them, as noted here.

Most commonly, we use the set command to assign values to variables. In many other programming languages, they use the = sign, like this:

dialogAnswer = result

You can’t do this in AppleScript (or rather you can, but it means something else, not variable assignment), so if you’ve come to AppleScript with a background in another language, you’ll need to make the mental adjustment.

What about result though? Where did that come from? This is a built-in property, filled with the value of the last command to be executed.

Take a moment to consider that. It means that the result property changes on (almost) every line of your script.

Before we continue working through the rest of Script 6, let’s take a closer look at the result property. Type this in, then compile and run it:




Notice that in the Events pane, result changes from 2, to 3 and finally (in the Results pane) to 6.




AppleScript can use the usual programming conventions for mathematical operators (+, -, /, *. For x % y, use x mod y). That also includes the = sign, where it means “is equivalent to” (aka “==” in many other programming languages) and not, as we mentioned above, “assign to”.

In this little script, we also learned how to use the log command to print the value of a variable to the Events pane. In Script Editor, you’ll need to do that a lot if you want to see the values of your variables at different times in your script. In Script Debugger, however, it’s rarely necessary as you can see the values in the Variables inspector view.

To verify this, try removing the two log statements and running the script again. The log statements no longer appear in the Events pane, but Script Debugger captures them anyway in the Variables inspector view.


Line 3
Line 3 of Script 6 is an if statement, a kind of control flow statement. The clause, in this case, takes the form of a block. That means it evaluates a condition on one line, executes any commands if the condition is met on subsequent lines (Line 4) and then provides an end statement (Line 5) to signal the end of the block.

The conditional here first examines the button returned property of the result, which, remember, we’ve captured in the dialogAnswer variable.

After the conditional has been evaluated and any commands executed if the condition was satisfied, the rest of the script continues to execute as normal. In Script 6 there were no more commands after the block, so the script ends.


Line 4
In Line 4 of Script 6, if the user clicked “OK”, we set a new variable, theName, and assign it the value of the text returned property of the dialogAnswer record. Because we ended the block and the script on the next line, we never actually got to use this new variable, but typically the point of doing this would be so that we can use that value somewhere else in our script.


Where we are: so far!
Woah! We’ve done a lot in this post! We’ve seen how to get data in to our scripts from users and how to get data out, through dialogs, notifications and the Events and Results panes. We’ve had a first go at writing a conditional, logging messages, and viewing variable values. We’ve also been introduced to the compiler’s error messages and AppleScript’s record class.

If it’s all a bit of a blur, don’t worry. We’ll be practicing all of this, and expanding our skills some more, in the next post in this series, hello, applescript 3: (don’t?) tell me to run!. Be sure to follow Applehelpwriter to be notified when a new post is published.

See you there! 🙂





For extra credit:
1. Try to modify Script 6 so that when you run it and type in your name, it looks exactly like this.




You’ll need to consult the docs for display dialog, so try to find and explore Script Debugger’s Dictionary viewer in order to do that.

2. Go back to Script 4. What happens if you set with icon to 3?
This is an example of a run time or ‘execution’ error. The script will compile fine, because the parameter, or value, for with icon only has to be a number in order to compile. AppleScript tells you ‘a resource wasn’t found’ because, unlike ‘icon 0, ‘icon 1’ and ‘icon 2’, there’s no such thing as ‘icon 3’.

That raises a number of questions: how can we tell what kind of parameter an argument or command takes? Why are there only three icon resources and where are they declared? How can I add other icons if I want to? And last, but most importantly, what else do we need to know about run time errors? All this, and much, much more, will be covered in the hello, applescript series. Stay tuned!





hello, applescript: what’s the use?



In the first of a series of AppleScript tutorials, this post explains why you might want to consider learning AppleScript.


What’s the use?

If you’re not sure whether you want to invest time in learning AppleScript, this post is for you. Here I’ll outline four good reasons to learn AppleScript. I’m sure they’re not the only ones, but they’re the main ones that come to my mind as a daily user of the language. If, after reading this post, you want to give it a try, be sure to follow this series, as we’ll be quickly moving on with hands-on examples and detailed explanations that will rapidly turn you into an AppleScript power user! At the end of this post, I’ll briefly discuss tools, so that you’re ready to get started when the next in this series, User In, User Out, is published.


1. Automation
First of all, AppleScript can interact with other applications. That means it can get one app to perform a function and pipe the result to another app to perform a different function that the first app didn’t have. There’s no limit to the number of apps and functions you can chain together in this way (other than your computer’s resources). Why would you want to chain apps together like that?

To achieve things that none of those apps can do on their own.

Imagine this scenario (scripts for this appear later in this series of posts): Suppose you run a small business and customer orders come in via email. With an AppleScript, you can have those emails automatically scanned, the customers’ order details extracted, and your Excel or Numbers spreadsheet updated accordingly. You could then have the product details forwarded to another person (Packaging?) and the customer details forwarded to a third (Marketing?). Your script could tell Word, or Pages, to print out a label, and tell Mail to now send an automated response back to the customer. There is no one program on your computer that can accomplish all that, but you can, with AppleScript.





Once set up, none of this requires any interaction on your part. You build the script, test it, and add it as a Mail rule. The rest happens automatically when the mail arrives in your Inbox; you don’t need to monitor it. You can go on holiday. This ability to automate is what makes AppleScript so unique.


2. Integration
AppleScript’s ability to chain or pipe application functions together is similar to the Unix command line ability to pipe utilities together, only it allows you to do it with full-blown applications. But you can use it to connect those applications to command line utilities, too. This is the second thing that makes AppleScript unique: integration across the entire macOS environment. You can even chain it to other programming languages.


For example, I could have AppleScript run some Python code, take the result and run that through a Perl script, and take the result of that and display it to the user (or myself) in a dialog box or notification (or send an email, or a Chat message, etc). And I can do that without having to mess about worrying how to create graphical user interface elements like you might do with Tcl/Tk (if you know what that is; if you don’t, forget it!).

The relationship between AppleScript and the shell is symbiotic. If you’re a shell diehard, you’ll be happy to know that you can actually create and execute AppleScripts in .sh files without ever going near an AppleScript editor.


3. Power
AppleScript can not only harness the power of other scripting languages, it can harness the power of macOS itself. The AppleScript-ObjectiveC bridge means you could, if you wanted to – and many programmers do – create full on native macOS Cocoa apps without ever getting into the intricacies of Xcode projects and workspaces. You can even code sign your AppleScript apps from within the script editor.





4. God-mode
Finally, AppleScript can drive the user interface and even drive apps that haven’t been specifically made to support AppleScript. If you find yourself repeatedly doing the same actions in the UI to achieve a task, you can cut-out the middle-man (you!) and tell AppleScript to click those buttons, move those windows or copy that text from Safari and paste it into Pages instead of laboriously and repeatedly doing it yourself. This creates an eery effect not unlike those old-time pianolas.

Look no hands!



Where’s the catch? To achieve the level of automation and time-saving we’ve been discussing, you’re going to have to invest some time up front learning how to script. It won’t always be easy, and you won’t always be happy that it’s not easy, but that’s the price of investing in learning anything.

If you’re ready to learn this amazing, unique language, let’s get tooled up!


Tools
I’ll keep this short. You can learn AppleScript the hard way using the built-in Script Editor, or you can learn AppleScript the easier way by using the free 3rd-party editor Script Debugger.





Script Debugger gives you a full-featured trial for 20 days, and after that if you don’t want to buy it you lose some of the more advanced features but you can use the rest indefinitely anyway. It works in rather the same way as BBEdit’s trial does, if you’re familiar with that.

If you save scripts in Script Debugger (so long as they’re not debug scripts, more on that later), you can run (and edit) them in Script Editor and vice versa. In other words, you’re not locked in to a proprietary tool.

I’m not even going to consider that you’d choose to learn AppleScript the hard way since the easier way is free, so all the examples in this series of posts will use Script Debugger. However, unless otherwise marked as SD-only or SD-paid-only, you can do all of the examples in the series in either tool.

Don’t worry, at this point, about how to use either Script Editor or Script Debugger. We’ll get into that in the next post: hello, applescript 2: User In, User Out. Follow Applehelpwriter to be notified when a new post is published.

🙂


%d bloggers like this: