Bash issues with osascript GUI commands - macos

I am trying to automate the process of launching an application in OSX and typing an administrator password at a security agent prompt. I was hoping to avoid the use of AppleScript GUI scripting however the underlying cause of the admin prompt is so convoluted and complicated I just won't go there.
Below is the script which works perfectly when run locally by an OSX administrator. Ie. from terminal adminaccount# /usr/local/bin/ReasonScript.sh
#/bin/sh
sudo /usr/bin/osascript <<EOF
launch application "Reason"
tell application "System Events"
repeat until (exists window 1 of process "SecurityAgent")
delay 0.5
end repeat
tell window 1 of process "SecurityAgent"
tell scroll area 1 of group 1
set value of text field 1 to "adminaccount"
set value of text field 2 to "adminpassword"
end tell
click button "OK" of group 2
end tell
end tell
EOF
exit 0
The Problem
I need to execute this script as a root user (not great I know but its how our deployment software does it). So I try it like root# /usr/local/bin/ReasonScript.sh and I get the following error
105:106: syntax error: Expected “,” but found “"”. (-2741)
I have gone through the script but I am not expert at AppleScript but I can't find this syntax error. But at the same time I do not expect this to work as the ROOT user doesn't have a GUI to access so maybe this is part of that failure.
Then I try and assume the local users permissions from root... ie root# sudo -u adminaccount /usr/local/bin/ReasonScript.sh
Unfortunately i get the following
shell-init: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
job-working-directory: error retrieving current directory: getcwd: cannot access parent directories: Permission denied
A thousand appologies if Stackoverflow is not the right place for this question. I'm so confused I don't know how to troubleshoot this further. Is it AppleScript, is it osascript, is it BASH or is it the administration structure of OSX.
I appreciate all the assistance I can get with this pickle.

From the man page:
osascript will look for the script in one of the following three places:
1. Specified line by line using -e switches on the command line.
2. Contained in the file specified by the first filename on the command
line. This file may be plain text or a compiled script.
3. Passed in using standard input. This works only if there are no
filename arguments; to pass arguments to a STDIN-read script, you
must explicitly specify ``-'' for the script name.
If you are going to use a heredoc, you will have to use the third option. Otherwise, you can either have an applescipt file or run it line by line with -e.

Related

Running a Service with sudo administrator privileges

I have the following shell script that I normally run successfully as a system service (created in automator:
#!/bin/bash
for f in "$#"
do ln -s "$f" "${f}.deleteThisExtensionAfterMoving"
echo "${f}.deleteThisExtensionAfterMoving"
done
However, when trying to use this to make symlinks in folders that I'm not the owner of, it fails.
I tried saving it as a script, then using applescript in automator as I've seen described elsewhere here:
on run {input, parameters}
do shell script ("sudo ~/Documents/z_misc/makesymlink '" & POSIX path of input & "'") with administrator privileges
end run
However, upon running the service, I see a "command not found" error.
When I tried saving the script as a .sh file and using that instead, it still didn't work. When I try running from terminal without the preceding "sudo" command, I get a "permission denied" error.
When I try running from terminal without the preceding "sudo" command, I get a "permission denied" error.
The "permission denied" error when attempting to execute a shell script (or binary executable) is typically caused because the file is not set as executable. Use the following command in Terminal:
chmod +x file
Or:
chmod +x /path/to/file
Quoting if there are spaces or escaping spaces with a backslash (\), but not both.
However, the "permission denied" error can also be caused if there is a privileges issue with where the shell script or binary executable is located.
Keeping executables in you Documents folder or any of the default folders, except for Public, within your Home folder can be problematic to Automator actions and for use in Terminal.
I created a bin folder in my Home folder and place my shell scripts and binary executables that I do not want elsewhere, e.g. /use/local/bin, and have added "$HOME/bin" to my PATH.
Here is what I'd use in the Run AppleScript action in my Automator Service/Quick Action:
Example AppleScript code:
on run {input, parameters}
repeat with thisItem in input
set thisItem to the quoted form of the POSIX path of thisItem
do shell script ("$HOME/bin/makesymlink " & thisItem) with administrator privileges
end repeat
end run
As coded, this allows for multiple Finder items to be passed to the Automator Service/Quick Action.
That all said, without seeing the contest of the makesymlink file there is not anything else I can think off at the moment.
From the linked Technical Note below:
Note: Using sudo(8) with with administrator privileges is generally unnecessary and creates security holes; simply remove the sudo.
Have a look at Technical Note TN2065 do shell script in AppleScript
If you are going to use the do shell script command, then I suggest you read the entire Technical Note.

How can I automate opening a Gradle failed test report in my web browser on demand after a build failure?

I have a Gradle Java project with multiple modules. When tests fail in one or more of the modules, an HTML test report is created under ${parentProject}/${childProject}/build/reports/tests/test/index.html. This test report is output to the Gradle command line as follows:
There were failing tests. See the report at: file:///path/to/parent-project/child-project-1/build/reports/tests/test/index.html
When a test fails in this manner, I often like to open the HTML test report in my web browser, so I can interactively view the failures in a manner that is easier for me to see at a glance than looking at the text output of the failures. I use the open command from my macOS Terminal for this purpose. Since the open target is a URL, it opens in my default browser, as desired.
open file:///path/to/parent-project/child-project-1/build/reports/tests/test/index.html
OPEN(1) BSD General Commands Manual OPEN(1)
NAME
open -- open files and directories
SYNOPSIS
open [-e] [-t] [-f] [-F] [-W] [-R] [-n] [-g] [-j] [-h] [-s sdk] [-b bundle_identifier] [-a application] file ... [--args arg1 ...]
DESCRIPTION
The open command opens a file (or a directory or URL), just as if you had double-clicked the file's icon. If no application name is speci-
fied, the default application as determined via LaunchServices is used to open the specified files.
If the file is in the form of a URL, the file will be opened as a URL.
Currently to do this, I use my mouse to scroll up to the report line in the output, copy the report path, paste it into the terminal after typing open , and then hit enter.
This involves using multiple input devices (mouse, keyboard), and searching and identifying the line. I would like to automate this (either within Gradle or within the shell) so that I can quickly open a failed test in my browser. I don't want it to automatically happen on failed tests, since I tend to be doing things in the background when running the full project build, and I don't want web browser windows just popping up on me.
I'm not really sure how best to begin. As far as I know, there isn't a way to get the previous process's output after the fact to scrape the failing test from (though if there is, that would be a potential avenue of attack). I'm not sure if Gradle has a way to get the failed test report as a follow-up task, while still failing the build (if it does, I could use that task to get the failure).
I suppose I could write a standalone task which checks the project's build reports for failures and apply it to each subproject, using the presence of an XML file in ${subproject}/build/test-results/test as an indicator that a test has failed (it looks like it's only being generated for failed tests, but I could be wrong).
So in short, is there a clean way to automatically open Gradle failed tests in my macOS web browser of choice as a simple shell script, alias, Gradle command, or the like that can be run after a test fails?
Assuming there is only one instance of the file:///.../index.html URL in the contents of the entire scrolling buffer of the tab, then the following example AppleScript code can do that:
tell application "Terminal" to ¬
set tabHistory to ¬
history of tab of ¬
front window as text
set fileURL to ¬
do shell script ¬
"grep -o 'file:///.*\\.html' <<< " & ¬
tabHistory's quoted form & "; exit 0"
if fileURL is not "" then ¬
do shell script ¬
"open " & fileURL's quoted form
Notes:
The example AppleScript code above acts on the selected tab of the front window in Terminal.
If there is a file:///.../index.html URL in the contents of the entire scrolling buffer it will be opened by the open command.
If there is more than one instance of the file:///.../index.html URL in the contents of the entire scrolling buffer of the tab, then make the following change in the example AppleScript code above to open the last instance of the file:///.../index.html URL:
Change:
set fileURL to ¬
do shell script ¬
"grep -o 'file:///.*\\.html' <<< " & ¬
tabHistory's quoted form & "; exit 0"
To:
set fileURL to ¬
last paragraph of ¬
(do shell script ¬
"grep -o 'file:///.*\\.html' <<< " & ¬
tabHistory's quoted form & "; exit 0")
The example AppleScript code can be saved as a shell script with a #!/usr/bin/osascript shebang, made executable and run from Terminal.
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.

How to start a .command script from a mac automator app

I'm trying to create a mac "app" using automator that basically calls a .command file to do all the work. The command file will be in the same dir as the .app but i'm falling at the first which is - get the current directory of the .app file thats been clicked to determine the file location of the .command file.
i've tried
SCRIPTPATH="$( cd "$(dirname "$0")" ; pwd -P )"
echo "-- $SCRIPTPATH"
This just returns my users director - basically ~
The app itself is in a dir on the Desktop example: ~/Desktop/foo/my.app
I've also tried
here="`dirname \"$0\"`"
echo "cd-ing to $here"
cd "$here" || exit 1
neither work.
ultimately i need to call my.command to run the command but need to know its actual position - or even relative to the app so that it'll fire. currently i get the error that it can't find the my.command as its not located in the root of my user account (since i wont have control over where it can be placed on the end users machine).
Any pointers on what i can do to solve this much appreciated.
Note: To answer - why am i using an app which has a terminal script to call a .command which is essentially a script - basically because if you do it this way a terminal doesn't actually pop up.. which for this demo is what i need to happen.
As you did not include explicit details of your Automator workflow, saved as an application, I'm presenting the following as an example of how to have and Automator app, e.g. my.app, execute the e.g. my.command script file, that which is located in the same folder as e.g. my.app is.
For the purpose of the example, I created a folder named foo on my Desktop, in which my.app was saved along with the my.command script file.
The Automator application workflow uses a Run AppleScript action to accomplish the goal.
Replace the default code with the following example AppleScript code:
set myCommandFilename to "my.command"
set myAppPathAlias to path to me
tell application "System Events"
set myDirName to POSIX path of container of myAppPathAlias
set myCommandFilePathname to myDirName & "/" & myCommandFilename
set myCommandFilenameExists to exists file myCommandFilePathname
end tell
if myCommandFilenameExists then
try
do shell script myCommandFilePathname's quoted form
on error eStr number eNum
display dialog eStr & " number " & eNum ¬
buttons {"OK"} default button 1 ¬
with title "File I/O Error..." with icon stop
end try
else
display dialog "A necessary file, ' " & myCommandFilePathname & ¬
"', is missing!" buttons {"OK"} default button 1 ¬
with title "Missing File..." with icon stop
end if
Note: Change my.command to the actual filename. The rest of the example AppleScript code should not need to be modified.
If my.app is launched and the my.command script file is not in the same folder as my.app, then an error message will be displayed, e.g.:
If my.app is launched and the my.command script file doesn't have its executable bit set, then this error message will be displayed, e.g.:
Also, if the my.command script file does not exit cleanly, it too will display an error message, e.g.:
The content of the error message will vary based on the content of the e.g. my.command script file, how it's coded and how it fails. This example is worst case scenario in that it lets you know something failed, but not what failed.
Note: The example AppleScript code is just that and 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.

How to run multiple lines of commands in Terminal from AppleScript?

Please refer to this question first,
unable to read opensslv.h:No such file or directory
Based on that I need to run the following three line Terminal commands using AppleScript,
/tmp/ssl/openssl-1.0.1h/Configure darwin64-x86_64-cc ––prefix=/usr no-threads shared
make -f /tmp/ssl/openssl-1.0.1h/Makefile
sudo make -f /tmp/ssl/openssl-1.0.1h/Makefile install
I tried two methods I created text files with .command and .sh extensions and added the above three lines. Then tried to run it from AppleScript as,
do shell script "/Users/Username/Desktop/RunScript.sh"
But got this error,
error "/Users/Username/Desktop/RunScript.sh: line 1: /tmp/ssl/openssl-1.0.1h/Configure: No such file or directory
/Users/Muhriz/Desktop/InstallOpenSSL.sh: line 2: make: command not found sudo: no tty present and no askpass program specified" number 1
This could work,
tell application "Terminal" to activate
tell application "Terminal"
do script ("/tmp/ssl/openssl-1.0.1h/Configure darwin64-x86_64-cc ––prefix=/usr no-threads shared") in window 1
do script ("make -f /tmp/ssl/openssl-1.0.1h/Makefile") in window 1
do script ("sudo make -f /tmp/ssl/openssl-1.0.1h/Makefile install") in window 1
end tell
But it asks for password in Terminal at the third line and waits for user response. The password dialog shown from the AppleScript (when using with administrator privileges) is OK. But it must no ask for password via Terminal when running the commands. It needs to ask only once when the AppleScript is executed and run all sudo related commands without asking for password in Terminal.
What code needs to be used to run from AppleScript?
Perform the following before running your scripts.
chmod a+x /Users/Username/Desktop/RunScript.sh
xattr -r -d "com.apple.quarantine" /tmp/ssl/openssl-1.0.1h
do shell script "/Users/Username/Desktop/RunScript.sh"
That doesn’t work because you can’t pass a path to the “do shell script” command, you can only pass it the contents of the actual script.
If you want to run a bash script that is contained in its own file, you can use TextEdit to open the bash script file and set the contents of the file to a variable, which you can then pass to “do shell script.”
tell application "TextEdit"
set theDesktopPath to the path to the desktop folder as text
set theShellScriptPath to theDesktopPath & "RunScript.sh"
open file theShellScriptPath
set theShellScript to the text of document 1
set theScriptResult to do shell script theShellScript
make new document
set the text of document 1 to theScriptResult
end tell

Executing Shell Scripts from the OS X Dock?

How do I set up a shell script to execute from the Mac OSX dock? It seems that simply creating a shortcut will open the file in my editor. Is there a flag I need to set somewhere to tell it to run instead of opening it for editing?
You could create a Automator workflow with a single step - "Run Shell Script"
Then File > Save As, and change the File Format to "Application". When you open the application, it will run the Shell Script step, executing the command, exiting after it completes.
The benefit to this is it's really simple to do, and you can very easily get user input (say, selecting a bunch of files), then pass it to the input of the shell script (either to stdin, or as arguments).
(Automator is in your /Applications folder!)
If you don't need a Terminal window, you can make any executable file an Application just by creating a shell script Example and moving it to the filename Example.app/Contents/MacOS/Example. You can place this new application in your dock like any other, and execute it with a click.
NOTE: the name of the app must exactly match the script name. So the top level directory has to be Example.app and the script in the Contents/MacOS subdirectory must be named Example, and the script must be executable.
If you do need to have the terminal window displayed, I don't have a simple solution. You could probably do something with Applescript, but that's not very clean.
On OSX Mavericks:
Create your shell script.
Make your shell script executable:
chmod +x your-shell-script.sh
Rename your script to have a .app suffix:
mv your-shell-script.sh your-shell-script.app
Drag the script to the OSX dock.
Rename your script back to a .sh suffix:
mv your-shell-script.app your-shell-script.sh
Right-click the file in Finder, and click the "Get Info" option.
At the bottom of the window, set the shell script to open with the terminal.
Now when you click on the script in the dock, A terminal window will pop up and execute your script.
Bonus: To get the terminal to close when your script has completed, add exit 0 to the end and change the terminal settings to "close the shell if exited cleanly" like it says to do in this SO answer.
I know this is old but in case it is helpful to others:
If you need to run a script and want the terminal to pop up so you can see the results you can do like Abyss Knight said and change the extension to .command. If you double click on it it will open a terminal window and run.
I however needed this to run from automator or appleScript. So to get this to open a new terminal the command I ran from "run shell script" was "open myShellScript.command" and it opened in a new terminal.
As long as your script is executable and doesn't have any extension you can drag it as-is to the right side (Document side) of the Dock and it will run in a terminal window when clicked instead of opening an editor.
If you want to have an extension (like foo.sh), you can go to the file info window in Finder and change the default application for that particular script from whatever it is (TextEdit, TextMate, whatever default is set on your computer for .sh files) to Terminal. It will then just execute instead of opening in a text editor. Again, you will have to drag it to the right side of the Dock.
In the Script Editor:
do shell script "/full/path/to/your/script -with 'all desired args'"
Save as an application bundle.
As long as all you want to do is get the effect of the script, this will work fine. You won't see STDOUT or STDERR.
I think this thread may be helpful: http://forums.macosxhints.com/archive/index.php/t-70973.html
To paraphrase, you can rename it with the .command extension or create an AppleScript to run the shell.
As joe mentioned, creating the shell script and then creating an applescript script to call the shell script, will accomplish this, and is quite handy.
Shell Script
Create your shell script in your favorite text editor, for example:
mono "/Volumes/Media/~Users/me/Software/keepass/keepass.exe"
(this runs the w32 executable, using the mono framework)
Save shell script, for my example "StartKeepass.sh"
Apple Script
Open AppleScript Editor, and call the shell script
do shell script "sh /Volumes/Media/~Users/me/Software/StartKeepass.sh" user name "<enter username here>" password "<Enter password here>" with administrator privileges
do shell script - applescript command to call external shell commands
"sh ...." - this is your shell script (full path) created in step one (you can also run direct commands, I could omit the shell script and just run my mono command here)
user name - declares to applescript you want to run the command as a specific user
"<enter username here> - replace with your username (keeping quotes) ex "josh"
password - declares to applescript your password
"<enter password here>" - replace with your password (keeping quotes) ex "mypass"
with administrative privileges - declares you want to run as an admin
Create Your .APP
save your applescript as filename.scpt, in my case RunKeepass.scpt
save as... your applescript and change the file format to application, resulting in RunKeepass.app in my case
Copy your app file to your apps folder
Exact steps to achieve that in macOS Monterey 12.3
Open Automator
File -> New
Choose Application
Go to Library -> Utilities
Double-click Run Shell Script
Type in whatever command you want to run. For example, try the command to toggle Dark Mode:
osascript -e 'tell app "System Events" to tell appearance preferences to set dark mode to not dark mode'
File -> Save
Drag the saved file to the Dock, done!
pip install mac-appify
I had trouble with the accepted solution but this command worked for me.
Install
pip install mac-appify
Run
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/appify ~/bin/webex_start.sh ~/Desktop/webex.app
Adding to Cahan's clear answer ... to open a shell script from the dock without passing any arguments to it, try:
open [name of your script].scpt"
example:
open "//Users/user/Library/Mobile Documents/com~apple~ScriptEditor2/Documents/myScript.scpt"
Someone wrote...
I just set all files that end in ".sh" to open with Terminal. It works
fine and you don't have to change the name of each shell script you
want to run.

Resources