Accessibility settings for non-GUI apps using AppleScript in OSX Mavericks? - macos

In previous versions of OS X, to allow AppleScript to be run you needed to check “Enable access for assistive devices” in the Accessibility pane of System Preferences.
With Mavericks, this is now a per-app setting that is enabled from Security & Privacy -> Accessibility. How do I enable assistive access if the script is being run from the command line with osascript from within a Jenkins task? As far as I understand, there is no GUI task to authorize then; I get no message dialog asking for permissions. The error message I get in the Jenkins output is:
take_screenshot_iossim.sh:246:303: execution error: System Events got an error: osascript is not allowed assistive access. (-1719)
I also tried adding all applications to the permissions dialog and still receive the permissions denied error.

Problem
If I understand correctly, you want to enable GUI scripting from a command line.
Solution
I believe you will need to use the following code to enable GUI Scripting from within an applescript. That script can then be executed from the command line. You may want to exclude the display dialog as needed -- this script just presents the dialog to confirm that the GUI settings have been made active.
if enabledGUISCripting(true) then
-- GUI Scripting statements go here
display dialog "GUI Scripting is enabled"
else
--non-GUI scripting statements go here
display dialog "GUI Scripting is disabled"
end if
on enabledGUISCripting(switch)
tell application "System Events"
activate
if not (UI elements enabled) then set (UI elements enabled) to true
return (UI elements enabled)
end tell
end enabledGUISCripting
The key parts of this are:
tell application "System Events"
activate
if not (UI elements enabled) then set (UI elements enabled) to true
end tell
You could combine the key parts mentioned above into a file and tell osascript to execute it using:
osascript file.scpt
If you want to send osascript multiple commands on a single line instead of using a script file you could try (note multiple -e flags per command):
osascript -e “line 1″ -e “line 2″ -e “line 3″
You may want to run this using sudo (if needed):
If you get an error such as this one when running such scripts from Terminal you will need to enable accessibility for Terminal in the privacy preferences (Mavericks, see image below)
execution error: System Events got an error: Can’t set UI elements enabled of application to true. (-10006)
System Preferences > Security & Privacy > Accessibility (Click to enable Terminal)

I worked round this by starting the jenkins slave by using JNLP rather than SSH. You can set this up in the slave node settings on the jenkins master.
To set this up i created an automator script which runs at login so the jenkins slave runs as a real user.
curl -o slave.jar http://server:8080/jnlpJars/slave.jar && java -jar slave.jar -jnlpUrl http://server:8080/computer/<slaveName>/slave-agent.jnlp -secret <secret from the node settings on master>
This causes osx to popup an enable application access to assistive devices popup for the automator script which then allows it to access everything.
For me this is not a complete solution as i have problems with JNLP slaves going offline more than the SSH launched slaves, which is how i found this issue :D

Another solution is to run the command by spawning a terminal which i guess is not in apple's banned list of things for assitive access.
After a bit of messing around i found the following worked over ssh
osascript -e 'tell application "Terminal" to do script "take_screenshot_iossim.sh"'
This then pops up the assitive dialog again and you can approve access
You need to setup the terminal to auto close after success otherwise you'll end up with millions of them :D

Related

Privacy tab using AppleScript

I am trying to access the Privacy -> Accessibility tab using Applescript. Can anyone help me?
I need to display a list of all the programs in the section:
Accessibility
Camera
Microphone
Photos
etc...
The request itself and the output in the terminal using osascript -e.
It is necessary to exclude interaction with the GUI. Here's what I managed to find
osascript -e 'tell application "System Events" to get the name of every login item'
I need to find the same solution for Accessibility? And get the result the same as in the screenshot below.
The main goals are
Locally get the information contained in Security & Privacy
2)Connect to mac OS via SSH and get the information contained in Security & Privacy. If this is not possible, then how to display the information using a single Apple script.
It is necessary to exclude interaction with the GUI (on the remote system).
Testing with the remote system being macOS Big Sur 11.6 and having checked [√] Allow full disk access for remote users in System Preferences > Sharing > Remote Login on the remote system, then the example shell script code executed in Terminal on the local system in a ssh session to the remote system will give you a raw dump of what's listed under Accessibility in System Preferences > Security & Privacy > Privacy without the need for UI Scripting with AppleScript.
sqlite3 '/Library/Application Support/com.apple.TCC/TCC.db' 'SELECT client FROM access WHERE service="kTCCServiceAccessibility";'
On the test system its output was:
/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/Support/AEServer
com.apple.AccessibilityInspector
com.apple.Automator
com.apple.ScriptEditor2
com.apple.Terminal
com.latenightsw.ScriptDebugger8
If you really have a need to use AppleScript you could, however, say you needed the output to be pretty. In other words, using an AppleScript script saved as a shell script using a #!/usr/bin/osascript shebang the output on the same remote system would be e.g.:
AEServer, Accessibility Inspector, Automator, Script Editor, Terminal, Script Debugger
Example AppleScript code:
#!/usr/bin/osascript
set theAccessibilityList to paragraphs of (do shell script "sqlite3 '/Library/Application Support/com.apple.TCC/TCC.db' 'SELECT client FROM access WHERE service=\"kTCCServiceAccessibility\";'")
set theAccessibilityApplicationNamesList to {}
repeat with thisItem in theAccessibilityList
if thisItem starts with "/" then
set shellCommand to (do shell script "f=" & quoted form of thisItem & "; echo ${f##*/}")
set end of theAccessibilityApplicationNamesList to shellCommand
else
try
set end of theAccessibilityApplicationNamesList to the name of application id thisItem
end try
end if
end repeat
return theAccessibilityApplicationNamesList
Notes:
I created, saved and made executable the example AppleScript code, shown above, on the local system and then copied it the from the local system to the remote system using scp.
Note: The example AppleScript code is just that and sans any included error handling does not contain any additional error handling as may be appropriate. The onus is upon the user to add any error handling as may be appropriate, needed or wanted. Have a look at the try statement and error statement in the AppleScript Language Guide. See also, Working with Errors. Additionally, the use of the delay command may be necessary between events where appropriate, e.g. delay 0.5, with the value of the delay set appropriately.
You should escape the nested quotes following way. And, activate the System Preferences.
osascript -e "
tell application id \"com.apple.systempreferences\"
activate
reveal anchor named \"Privacy_Accessibility\" in pane id \"com.apple.preference.security\"
end tell
tell application id \"sevs\" to tell process \"System Preferences\"
repeat until window \"Security & Privacy\" exists
delay 0.02
end repeat
tell scroll area 1 of group 1 of tab group 1 of window \"Security & Privacy\"
get value of static text 1 of UI element 1 of rows of table 1
end tell
end tell"
Or, if needed table view (on right) of needed item (on left) is already opened, you can use following osascript on the Catalina:
osascript -e "
tell application id \"sevs\" to tell process \"System Preferences\"
set frontmost to true
tell scroll area 1 of group 1 of tab group 1 of window \"Security & Privacy\" to get value of static text 1 of UI element 1 of rows of table 1
end tell"

OSX bash minimize window

In the Mac and using the bash shell, I want to execute a file that contains a single command (to start Jupyter Lab) and immediately minimize the terminal window.
Is there a way to do this WITHOUT installing third party software?
Yes, just use osascript and Applescript:
osascript -e 'tell application "Terminal" to set visible of front window to false'
Building on Paul R's answer, which in my testing appears to make the window fully hidden and unrecoverable, you can use the following to minimise the window to the dock if access is required again later:
osascript -e 'tell application "Terminal" to set miniaturized of every window to true'
You can create a file that with the command extension, for example jupiter-lab.command.
You add execution rights on it (chmod +x jupiter-lab.command). You edit the file and insert commands like in a bash script.
For example to open App Store, you could insert :
open "/Application/App Store.app"
The first time you double click on it, you will get a popup that tells you that the command has ended quickly. Just check the Suppress this message permanently not to see it anymore.
Note : the terminal will not be minimised but will be closed.

Mute Macbook pro when computer is shutting down

I'm thinking of using the Mac's applescript to make a program that mutes the system when it is shutting down.
Though I'm new to applescript and I don't know how to use the IF-statement to determine if the system is shutting down. I've done some googling and I've found that the finder app is the app that is "controlling" the shutdown, but i don't know how to check if the state is "shut down". Can anybody assist me in this matter?
AppleScript has no direct mechanism for detecting a shutdown/logout.
It does have a mechanism for creating applications that can react to themselves being quit.
Thus, you can:
use AppleScript to create a stay-open application (.app bundle) with a standard on quit handler, in which you perform the desired action (
make sure that the application is launched on login - in the simpler case as a Login Item (via System Preferences, see below), or, with more flexibility but complexity, as a launch agent (see https://stackoverflow.com/a/22872222/45375).
Instructions:
Open Script Editor and open a new script window.
Paste the following code:
# This standard handler is called when the application quits.
on quit
# Mute the system volume.
# !! See caveat below.
set volume with output muted
continue quit # signal to the system that it's OK to quit
end quit
Save the script as a stay-open application:
with File Format Application
check Stay open after run handler
Open System Preferences > Users & Groups > Login Items, drag the newly saved *.app bundle into the list, and check the checkbox next to it, so as to make it launch hidden.
The final step is to hide the new application's Dock icon, as there's no reason for it to have one:
From Terminal, run the following:
defaults write /full/path/to/newApp.app/Contents/Info.plist LSUIElement 1
Note: You could use LSBackgroundOnly too, but the advantage of LSUIElement is that you can still display UI elements if you want to, such as for debugging.
Important: Substitute the full path of your new app for /full/path/to/newApp.app; the command will only work if you specify the full path to the Info.plist file.
To test, start the new app interactively, and make sure that no Dock icon appears. (You can quit the app via Activity Monitor).
CAVEAT: If the intent is to suppress the system startup sound, set volume with output muted has two drawbacks:
it will not work if headphones happened to be plugged at the time of shutdown
you will have to unmute the volume on startup (however, you could do that in an on on run handler in the same app).
Consider the alternative approach below, which requires admin privileges to set up and invokes nvram SystemAudioVolume=%80 with root privileges, which bypasses the above drawbacks.
You could run do shell script "nvram SystemAudioVolume=%80" user name "someAdminUsername" password "matchingAdminPassword" with administrator privileges from the above AppleScript app, but you'd have to hard-code the password, which is not advisable for security reasons.
Alternative approach, using a system-wide logout hook via com.apple.loginwindow.
There's a deprecated mechanism for running a script on logout that, however, still works as of OSX 10.10; given that there's no direct non-deprecated equivalent, it may continue to be supported.
Note that you do need admin privileges:
sudo defaults write com.apple.loginwindow LogoutHook <yourScript>
<yourScript> must be an executable, such as a shell script; note that the executable is run in the context of the root user.
In case you're thinking of muting the startup sound, invoke the following shell command from that script:
nvram SystemAudioVolume=%80 # to try this interactively, prepend `sudo `
This will mute sounds until after a reboot, effectively muting the startup sound, without keeping the sound muted.
Note that the nvram command requires root privileges, which are by definition in effect in a script run via the com.apple.loginwindow logout hook.; by contrast, to try the command interactively, use sudo nvram SystemAudioVolume=%80 - otherwise, you'll get the following, unhelpful error message: nvram: Error setting variable - 'SystemAudioVolume': (iokit/common) general error
Honestly, it is better to make a deterministic solution. What I mean is, is that you make a script that:
Mutes your computer.
Shuts it down.
Then you take your script and create an Automator service, that you can assign to some shortcut, to make it easier for you to use it. ctrl-opt-cmd-eject or something. :)
This is just how I would have solved it, if I have the need, it is short and sweet to make work, and should work reasonably well.
If you want to use the LogoutHook mentioned in #mklement0's answer.
You can use the normal Applescript command set volume with output muted.
You just need to add the osascript shebang to the top of the Applescript document
i.e
#!/usr/bin/osascript
set volume with output muted
And then save the file as applescript text file.
In the save dialogue use : file format: Text )
It will get the extension .applescript
Once it is saved, use Terminal.app to chmod the script as you would a normal shell script which in effect it is.
i.e
/bin/chmod +x foo.applescript
Then add it to the loginwindows LogoutHook.
sudo defaults write com.apple.loginwindow LogoutHook foo.applescript
I Know this is an old post but for anyone still looking how to do this(like I was) I have a simple method.
Before I started Scripting I created a new folder in my home folder called toolbar scripts.(this is optional)
With the desktop showing Finder click on Go >Utilities >Script Editor.
In the window that opens type in or copy and paste the code
set volume with output muted
tell application "finder"
shut down
end tell
Click on the last button above the script you added - it should be compile. If you cannot find that button then on the top click on Script >Compile
Click on File >Save in the save as I called mine shutdown and chose the script folder (this is optional)
Down the bottom of the dialog box at file format click on the arrow and change the format to application and click on save.
Open the folder you saved it in and drag the icon to the dock. Click on the icon you just put in the dock.
now if all is right this should mute the volume and shutdown the computer.
This will not shutdown the computer if you still have anything open.
Cheers
Peter
first, you should create a sound-off script (with terminal)
sudo nano /Library/Scripts/sound-off.sh
after filling it with these lines:
#!/bin/bash
osascript -e ‘set volume output muted 1’
and make a sound-on script like that
sudo nano /Library/Scripts/sound-on.sh
and fill it with:
#!/bin/bash
osascript -e ‘set volume 4’
then access them as executing files
sudo chmod u+x /Library/Scripts/sound-off.sh
sudo chmod u+x /Library/Scripts/sound-on.sh
and the last part is set them when the mac device is turn off and on:
sudo defaults write com.apple.loginwindow LogoutHook /Library/Scripts/sound-off.sh
sudo defaults write com.apple.loginwindow LoginHook /Library/Scripts/sound-on.sh

How can I launch an AppleScript application and run shell scripts from another AppleScript?

Here are my files:
launcher.applescript
tell application ":path:to:applescript:apps:shell-script-launcher.app" to launch
shell-script-launcher.app [AppleScript, saved as Application]
do shell script "say starting script"
Desired behavior:
Run "launcher.applescript" from AppleScript Editor
Listen for "starting script"
Actual behavior:
Running the "shell-script-launcher.app" by opening it manually in the finder yields expected behavior
Running the "launcher.applescript" opens the "shell-script-launcher.app" but it never executes the shell script.
I've tried saving the app as "Run Only" as well as "Stay Open". Still no progress. What do you recommend. The final result must be an Application instead of an Applescript.
Conceptually:
the run command launches and runs an application hidden
the activate command launches, runs, and activates the application (makes it the frontmost application)
launch, according to Apple, "Launches an application, if it is not already running, but does not send it a run command."
for AppleScript-based applications this should mean that they're loaded, but not executed (i.e., their - implicit or explicit - on run handler is NOT invoked), but in practice that is not true up to 10.9 - see below.
it is unclear (to me) what exactly that means for non-AppleScript-based applications
Here's how Apple thinks it works with AppleScript-based applications, which is only true starting with OSX 10.10 (Yosemite):
A script can send commands to a script application just as it can to other applications. To launch a non-stay-open application and run its script, use a launch command followed by a run command, like this:
launch application "NonStayOpen"
run application "NonStayOpen"
The launch command launches the script application without sending it an implicit run command. When the run command is sent to the script application, it processes the command, sends back a reply if necessary, and quits.
Broken behavior on OSX 10.8, 10.9 (fixed in OSX 10.10):
launch by itself is enough to run the application and is indeed the only command that works with AppleScript-based applications.
Any attempt to execute run or activate (whether in addition to launch or not) runs the application - even twice when run from AppleScript editor(!; just once with osascript) - but reports failure <appName> got an error: Connection is invalid.
This strikes me as bug.
Not sure how OSX versions <= 10.7 behave.
Note: I've witnessed the non-executing behavior with launch once, but every non-stay-open AppleScript-based test app I've created from scratch on OS X 10.9.2 and OS X 10.8.5 also executes the script with launch - contradicting what the documentation says.
Please let me know if your system behaves differently and/or how older versions behave. On what OSX version was the app that doesn't execute with launch created?
On OSX 10.10, behavior is consistent with the documentation, with one thing worth noting:
If the intent is to launch and run in one step, run application is sufficient - no need for a separate launch application command first.
Options
#user309603's pragmatic solution simply uses do shell script with the standard open utility to bypass the problem - this should work, regardless of whether the application is AppleScript-based or not:
do shell script "open " & ¬
quoted form of POSIX path of ¬
alias ":path:to:applescript:apps:shell-script-launcher.app"
If you know the type of application you're invoking up front:
to run an AppleScript-based app: best to use run script file, as #regulus6633 recommends - this has the added advantage that the invoked AppleScript-based application can return objects directly to the caller:
run script file ":path:to:applescript:apps:shell-script-launcher.app"
Note: There's also load script file, which indeed lets you merely load script code without executing it right away.
to run non-AppleScript apps: use run / activate to run the app hidden / frontmost:
run application ":path:to:applescript:apps:shell-script-launcher.app"
You could use run even with AppleScript-based applications and simply ignore errors with try ... end try, as #atonus suggests - the downside is that you won't be able to detect actual failure to invoke the application.
You can mitigate this by selectively ignoring only the specific Connection invalid error (which assumes this error would not legitimately occur) [no longer needed on OSX 10.10]:
try
run application "Macintosh HD:Applications:_Sandbox-AppleScript0.app"
on error number -609 # 'Connection is invalid' error that is spuriously reported
# simply ignore
end try
Finally, on OSX <= 10.9, you could try to simply use the launch command (though that didn't work for the OP, possibly due to working on a <= 10.7 OSX version):
launch application ":path:to:applescript:apps:shell-script-launcher.app"
However, that is not advisable for two reasons:
In OSX 10.10, Apple has fixed the launch behavior to no longer execute also, so your code will break when run there.
While non-AppleScript apps typically do run (hidden) when invoked with launch, the documentation says that AppleScript "does not send it a run command" and "allows you to open an application without performing its usual startup procedures, such as opening a new window" - what that exactly means is not clear and different applications seem to handle this differently.
Applescript has the "run script" command. It works on applescripts or applescript applications. So if I have your app on my desktop then this works...
set appPath to (path to desktop as text) & "shell-script-launcher.app"
run script file appPath
Have you tried open?
do shell script "open 'path/to/applescript/apps/shell-script-launcher.app' && say starting script"
Put it between "try" keywords.
try
tell application ":path:to:applescript:apps:shell-script-launcher.app" to activate
end try
Save your script as an application.
Add the desired script into the Script folder (see path below)
Run as follows, change per type of script you want to run...
property theApplicationPath : the path to me as text <br/>
property theShellScriptPath : theApplicationPath & "Contents:Resources:Scripts:test.command"<br/>
property theShellScript : the quoted form of POSIX path of theShellScriptPath<br/>
<br/>
tell application "Terminal" to (do shell script "/bin/bash " & theShellScript)
<br/>
Boom, Bob's your uncle! At least for me.
It is quite simple, you just have to use the normal do shell script, for example:
do shell script "open " & ¬
quoted form of POSIX path of ¬
alias ":path:to:applescript:apps:shell-script-launcher.app"
This may be helpful but I'm not an expert on this subject. I this case I found the double launching behaviour (on Yosemite, I haven't used any other version of OS X) very annoying and digging around I found one can check if it is already running.
This script is so I can launch a new terminal whenever I like.
if application "Terminal" is running then
tell application "Terminal"
activate
do script ""
end tell
else
tell application "Terminal" to activate
end if

Close Terminal window from within shell script (Unix)?

Is there a way to close a Terminal window from within a shell script? I have a .command file that should just get out of the way once it's done.
Using exit 0 will cleanly terminate the script.
Whether Terminal window stays open is user-configurable. The default is to always stay open. To change this:
Terminal.app > Preferences > Profiles > Shell
- "When the shell exists:"
> Close if the shell exited cleanly
- "Ask before closing:"
(•) Never
-- OR --
(•) Only if there are....
When "Close if shell exited cleanly" is used, the script will close the window if the exit result is 0, which is the default if nothing went wrong.
Since you don't want to delete all Terminal windows, first change the name of your window from "Terminal" to something else:
echo -n -e "\033]0;My Window Name\007"
Then at the end of the script, use:
osascript -e 'tell application "Terminal" to close (every window whose name contains "My Window Name")' &
You can use apple script to quit the terminal app. Add the following to your script -
osascript -e 'tell application "Terminal" to quit'
This will give you a popup confirming to close the app. You can disable this in Terminal preferences.
Alternatively, you can also use killall command to quit the app. The following would work just as well.
killall Terminal
Note:
Just as a side note, you can freely add the above commands to your script and it would work as you want. However, there are few caveats. First being you will limit the ability of your script to work on different boxes. Secondly, it would be safer to use nohup so that any commands that are currently running won't quit due to quitting of the Terminal app.
This works for me:
#!/bin/sh
{your script here}
osascript -e 'tell application "Terminal" to close (every window whose name contains ".command")' &
exit
This will work for closing just your windows opened with a .command file but leave things already running in other terminal windows. I know that I almost always have either sass or grunt watch something so I don't want to quit terminal totally.
closeWindow() {
/usr/bin/osascript << _OSACLOSE_
tell application "Terminal"
close (every window whose name contains "YourScriptName")
end tell
delay 0.3
tell application "System Events" to click UI element "Close" of sheet 1 of window 1 of application process "Terminal"
_OSACLOSE_
}
This will close the Terminal window for your script and keep any other Terminal windows open as long as their window titles don't match. For it to work Terminal will have to be added to the list of applications permitted to use the Accessibility framework. You can also cycle through Terminal windows with a repeat command and close every window x that contains a UI element "Close" on sheet 1.
I find the best solution for this is to use Automator to create a true OSX application which will work the same way regardless of how your system is configured. You can have the Automator run your shell script, or you can embed the shell script itself in Automator.
Here is how you do it:
Run Automator (in Applications).
Choose "New Document" and when it
asks "Choose a type for your document" choose "Application"
In the
left panel, select "Utilities" then "Run Shell Script".
Type in your
script commands in the workflow item in the right panel. You can either call another
shell script, or just put your commands in their directly.
Save the
Application, which will be a full-fledged Mac App. You can even
cut-and-paste icons from other apps to give your script some
personality.
#!/bin/bash -x
{your script here}
. exit 0
kill -9 $PPID
you can also create a shortcut for your script:
cp yourscript.sh ~/bin/yourshortcutnamewhateveryouwant
then type
yourshortcutnamewhateveryouwant
will run whatever is writen into script at any directory.

Resources