Bash Script: Enable Access to Assistive Devices Programmatically in OS X Mavericks 10.9.x – Simulate Keystrokes

Using a bash script to enable access to assistive devices is possible in Mavericks (and also Yosemite) despite the move to a per-app database.  This is useful for entering keystrokes or clicking GUI buttons via a bash script.

Bash script to log into the GUI in OS X Mavericks

Prior to OS X Mavericks, enabling access to assistive devices was relatively easy.  Running the command

sudo touch /private/var/db/.AccessibilityAPIEnabled

would enable it.  But now each app now needs to be allowed or disallowed access.

I often used Applescript/osascript to simulate keystrokes or click GUI buttons, which was great for automating “un-scriptable” tasks on multiple computers.  One particular feature I always found incredibly useful was logging a user in via the loginwindow by sending it a script from a remote machine.  This proved useful in a lab environment when I wanted to open a specialized piece of software to make sure it worked on all of the machines.

The script would simulate keystrokes and fill in the username and password fields and then press enter or click login.  Unfortunately, Mavericks does not allow Applescript (or more accurately, /usr/bin/osascript ) by default, which is what I used to accomplish this from my script.  Trying to run this script returned an error:

62:115: execution error: System Events got an error: osascript is not allowed assistive access. (-10006)

The first thing I tried was to drag /usr/bin/osascript  into the Accessibility window of the Security & Privacy Preferences pane, which is how you can add other apps.  This did not work as the command-line tool was not an .app .

Needless to say, after struggling to figure out how to enable this through a script, I finally found a way.

Enable Access To Assistive Devices via bash

Each entry in the Accessibility window is actually part of a database file.  Using sqlite3 , this file can be manipulated to add, remove, or modify items.  To get osascript  to work at the login window and be allowed access to assistive devices, run this command:

If you are using tccutil.py:

sudo tccutil.py -i com.apple.RemoteDesktopAgent

Or you can use sqlite3

sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.apple.RemoteDesktopAgent',1,1,1,NULL)"

To remove it:

sudo tccutil.py -r com.apple.RemoteDesktopAgent
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "DELETE from access where client='com.apple.RemoteDesktopAgent'"

or completely wipe out every entry with:

tccutil reset Accessibility

osascript  must be some part of /System/Library/CoreServices/RemoteManagement/ARDAgent.app , because another script I was working on triggered the prompt to allow it access.

ardagent_reqestingaccessibility

After enabling it in System Preferences and rebooting,

ardagent_enabled

I was able to run the script I have used for years that enters a users credentials into the login window fields via a script sent from Apple Remote Desktop.  The script is below, but I also have multiple versions of it on my Github page.  Even one written in Python.

When enabling this, I also add a few other things that may come in useful:

sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.apple.LockScreen',1,1,1,NULL)"
sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','com.apple.systemevents',1,1,1,NULL)"
sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','/usr/bin/say',1,1,1,NULL)"
sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "INSERT or REPLACE INTO access VALUES('kTCCServiceAccessibility','/usr/bin/osascript',1,1,1,NULL)"

This allows me to use things like the lock screen or the say  command from the login window.  In my scripts, I use it as a visual indicator that the job is done without having to log in.  I can either listen for the command to complete or the lock screen to disappear.

Another Solution

Apple’s utility, tccutil only supports one command in Mavericks.  I wrote my own version of it called tccutil.py.  You can get it below, or look at the source code.

This is just a little Python command line utility that can be used in scripts.  I’m sure Apple will expand their utility, but for now, this is something you can use.

Scripting Your Own GUI Actions

If you want to automate mouse clicks or keystrokes, I would suggest using UIElementInspector, or Accessibility Inspector, as it is called now (part of Xcode).  This works great to find out what window, menu, or button names are called, so you can use them in your AppleScripts or bash scripts (osascript ).

uielementinspector_gui

If you are using Mavericks, you will have to, ironically, allow it access to accessibility by either dropping it in the list, or following the prompts when you run the app for the first time.

addtoaccessibility

Troubleshooting

Adding osascript to the accessibility database doesn’t always mean your app or script will run without producing the error.  Often, you need to add the app that is being manipulated.  For example, if you had an AppleScript that clicked a menu in TextEdit, you would need to add TextEdit to the accessibility database.

15 Replies to “Bash Script: Enable Access to Assistive Devices Programmatically in OS X Mavericks 10.9.x – Simulate Keystrokes”

  1. Thanks for the python script. However, for some reason the logon script works to enter the credentials, but does not work to enter the return key at the end. Therefore, the machines just sit there with the credentials. Any ideas as to why this would happen?

  2. How does this work in El Capitan? I tried the sqlite3 script and it ran without error, but the app was not listed in System Preferences -> Security & Privacy -> Privacy -> Accessibility.

        1. Oh ok. I haven’t tried that way for a while, but tccuil.py uses the same commands essentially, so it should work. What app are you trying to add?

          1. I was trying to add ADPassMon. I installed the python script and it worked beautifully. Thanks!

          2. I do have one question remaining though — when I run the tccutil.py script it adds ADPassMon to the accessibility list. But on the first launch of ADPassMon it still prompts the user to be added to the list. The warning says “ADPassMon’s “Change Password” feature requires assistive access to open the password panel. Enable it now? (requires password). Have you ever run into this?

          3. It’s set to enable them by default, but I haven’t tried with ADPassMon, but you can enable it with tccutil as well: tccutil -e and then the bundle ID of ADPassMon.

          4. Thank you for the info, Jacob. After digging further, I found that tccutil.py was working exactly as you said – the utility had added and enabled the app in the assistive devices list. But the way ADPassMon is coded, it doesn’t actually check the list. It just asks the user upon first launch to authenticate, adds them to the list and then sets preference telling itself not to check the assistive list in the future. So I added the app to the list via tccutil.ph, then set ADPassMon’s preference via script and then ran “killall cfprefsd” to force the app to re-read its preference file. Thanks again.

          5. Ahh that makes sense! Sounds like you found the perfect solution! I’m glad it works now. I’m sure this will be useful next time I use it.

  3. Trying to do this in Sierra right now but it’s saying there are 7 columns and only 6 have been specified. This might need an update?

    The table looks like this:

    service TEXT NOT NULL,
    client TEXT NOT NULL,
    client_type INTEGER NOT NULL,
    allowed INTEGER NOT NULL,
    prompt_count INTEGER NOT NULL,
    csreq BLOB,
    policy_id INTEGER,
    PRIMARY KEY (service, client, client_type),
    FOREIGN KEY (policy_id) REFERENCES policies(id) ON DELETE CASCADE ON UPDATE CASCADE

Leave a Reply