Terminal Notifier commands hanging

bentoms
Release Candidate Programs Tester

Hi There,

I have a re-wrapped version of Terminal Notifier that i wish to use to notify end user of policies etc..

I have a collection of scripts that work locally as the user as when as root from the terminal (via su).

But they seem to either hang or fail with a syntax error when run by Casper. Any pointers? Examples below:

#!/bin/sh

loggedInUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`

if [[ $loggedInUser != root ]]; then

    echo "User $loggedInUser is logged in..."

    # Display alert to the user
    su "$loggedInUser" -c `/usr/local/bin/Company Alerts.app/Contents/MacOS/terminal-notifier -title "Updates Are Awaiting Install" -message "These updates will be installed when you next logout, restart or shutdown" -groupid updates`

else 

    echo "No User logged in..."   


fi
1 ACCEPTED SOLUTION

bentoms
Release Candidate Programs Tester
15 REPLIES 15

bentoms
Release Candidate Programs Tester

This example will hang:

#!/bin/sh
loggedInUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`

if [[ $loggedInUser != root ]]; then

    echo "User $loggedInUser is logged in..."

    # Display alert to the user
    sudo -u "$loggedInUser" /usr/local/bin/Company Alerts.app/Contents/MacOS/terminal-notifier -message "These updates will be installed when you next logout, restart or shutdown" -title "Updates Are Awaiting Install" -groupid updates

else 

    echo "No User logged in..."   


fi

bentoms
Release Candidate Programs Tester

hmm.. so does this...

#!/bin/sh
loggedInUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`

if [[ $loggedInUser != root ]]; then

    echo "User $loggedInUser is logged in..."

    # Display alert to the user
    su -c `/usr/local/bin/Company Alerts.app/Contents/MacOS/terminal-notifier -message "These updates will be installed when you next logout, restart or shutdown" -title "Updates Are Awaiting Install" -groupid updates` -s /bin/sh "$loggedInUser"
else 

    echo "No User logged in..."   


fi

bentoms
Release Candidate Programs Tester

mm2270
Legendary Contributor III

Ben, the only effective way I've ever been able to get Terminal Notifier to work 100% of the time is with the use of a LaunchAgent to call it up. Thee issue has more to do with the additional sandboxing in Lion and now more so with Mountain Lion that anything else. Apparently attempting to display a Notification Center message not AS the logged in user will get blocked or fail.

Josh_S
Contributor III

Give this a shot.

#!/bin/sh

loggedInUser=`/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'`
if [[ $loggedInUser != root ]]; then
    echo "User $loggedInUser is logged in..."
    # Get the PID of Dock.app
    loggedInPID=$(ps -axj | awk "/^$loggedInUser/ && /Dock.app/ {print $2;exit}")
    # Display alert to the user
    launchctl bsexec "${loggedInPID}" sudo -iu "${loggedInUser}" "/usr/local/bin/Company\ Alerts.app/Contents/MacOS/terminal-notifier -message "These updates will be installed when you next logout, restart or shutdown" -title "Updates Are Awaiting Install" -groupid updates"
else 
    echo "No User logged in..."
fi

bentoms
Release Candidate Programs Tester

Thanks Josh, i'll give that a go..

Looks like i could've done with that bit of information some months ago https://github.com/alloy/terminal-notifier/issues/44 might have been what i was missing.

The bonus of cocoaDialog is that i can set the notifications to be persistent with little effort.

mm2270
Legendary Contributor III

@Josh_S,

Thanks for posting your version of a script for this. I'm very interested in getting terminal-notifier to work with a regular script downloaded from the JSS and not using the LaunchAgent method I came up. I tried out your script and unfortuantely it seems the only way it has worked is if the terminal-notifier app is in a path WITHOUT spaces. Any time its located in a path with spaces, no matter what I've tried, it fails, claiming no such file or directory. I've tried setting up the path as a variable and placing it later in the script with quotes, without quotes, curly bracing it, quoting AND curly bracing it and finally just putting the path directly in the script line with spaces escaped. None of these have worked. it still fails every time saying it doesn't exist. I'm at a loss. Usually one of the above methods gets around space issues, but not this time. Must be something with the bsexec function that I just don't understand.

Here is what the policy log states (only the relevant error lines):

-bash: /Library/Application: No such file or directory
launchctl bsexec failed: No such file or directory

Using other paths with spaces and other methods of escaping all yield the same type of error.

Any thoughts?

Josh_S
Contributor III

I forgot to test in a path that included a space. Try double-escaping the space. I just got the following to work.

launchctl bsexec "${loggedInPID}" sudo -iu "${loggedInUser}" "/Library/Application\ Support/JAMF/terminal-notifier -message "These updates will be installed when you next logout, restart or shutdown" -title "Updates Are Awaiting Install" -groupid updates"

I really hate working with spaces in scripts for this very reason. You could also create a temporary, or permanent, symbolic link to the terminal-notifier command that doesn't include spaces.

ln -s /Library/Application Support/JAMF/terminal-notifier /tmp/terminal-notifier
# The rest of the script
rm /tmp/terminal-notifier

mm2270
Legendary Contributor III

@ Josh,

Thanks for the quick response and help on this. Been playing with it, and I figured out what I was doing wrong. Your tips helped, but it actually turned out to be my ignorance in how the script was actually telling terminal-notifier to do its thing.

See, I didn't realize that the whole line after the sudo -iu including the path to terminal-notifier was one command enclosed in quotes being passed in. I was attempting to use variables for the -title and -message rather than being hardcoded in, among other things, so it can be flexible. I mistakenly did not enclose the line in quotes, but I had the variables for title and message quoted. It was getting tripped up somewhere along there because of that. Once I understood that, I was able to make the necessary adjustments without needing to double escape the path to the app or use a symlink.

Sp thanks. So far testing is going well! Seems to be working like a charm via policy and I can assign parameters for the title, message, use -active (or -open) and a click-back action. Sweet!

tron_jones
Release Candidate Programs Tester

Solved

Ended up trying Josh's line and Bens link and found that I had the syntax wrong. Was using "$4" instead of the correct "$4"

@ mm2270
Mind sharing the quoting part for the parameters to work. I have everything working in shell but am having the same problem with the syntax for the parameters to work in a policy or with remote.

launchctl bsexec "${loggedInPID}" sudo -iu "${loggedInUser}" "/Library/Application\ Support/JAMF/terminal-notifier/terminal-notifier.app/Contents/MacOS/terminal-notifier" -message '$4' -sound 'default' -title '$5' -execute '$6'

jmb03012
New Contributor III

@Josh_S

I have a similar issue, I ended up using asuser for my 10.10 and 10.11 machines, but I'm having problems getting bsexec to work for my 10.9 and older.

Initially I was getting

/bin/launchctl bsexec "${LoggedInPID}" sudo -iu "${LoggedInUser}" "/bin/launchctl load /Library/LaunchAgents/com.bloomberg.BNotifier.plist"
sudo: unable to execute /bin/bash: Bad address
launchctl bsexec failed: No such file or directory

Then I thought OK, I didnt need to escape out the spaces on launchctl and load with asuser but maybe I need to here so I ran

/bin/launchctl bsexec "${LoggedInPID}" sudo -iu "${LoggedInUser}" "/bin/launchctl load /Library/LaunchAgents/com.bloomberg.BNotifier.plist"
-bash: /bin/launchctl load /Library/LaunchAgents/com.bloomberg.BNotifier.plist: No such file or directory
launchctl bsexec failed: No such file or directory

Similar but slightly different error.

Any thoughts?

UPDATE:
So I do have the syntax correct, I've noticed that if I run the command several times it eventually works, usually on the second or third run so I think sytax is good, but I cant explain why it doesnt consistently work (when it does fail it gets the same error as above).

May
Contributor III

Hi @jmb03012 did you ever resolve this ?

I'm having intermittent success loading a LaunchAgent from a script run as root

sudo: unable to execute /bin/bash: Bad address launchctl bsexec failed: No such file or directory

i'm using

/bin/launchctl bsexec "${loggedInPID}" sudo -iu "${loggedInUser}" "launchctl load /Library/LaunchAgents/local.adpassmon.job.plist"

sometimes it loads the agent but most of the time it wont.

mm2270
Legendary Contributor III

@May What OS? The launchctl bsexec command no longer works with El Capitan and only marginally worked under Yosemite. The Bad address error is often the result of it running on 10.10.
You should now use launchctl asuser as mentioned on this thread: https://jamfnation.jamfsoftware.com/discussion.html?id=9902
Look toward the end of the thread for the solution.

May
Contributor III

Thanks @mm2270

It's failing on 10.9, though i need it to work on 10.9 to 10.11, looking into asuser now, thank you.

We'll have some 10.9 machines around for a little while so i'll use @jmb03012 approach from here

jmb03012
New Contributor III

@May we ended up doing a form of the below, in the case of this specific example its a preinstall script that is in the installer/upgrade package.

#!/bin/sh
## preinstall

#Jordan Bender, Bloomberg LP, 2016
#Version 1.16

#Checks if <myapp> is installed on the machine, and if so unloads the LaunchAgent, and then removes existing <myapp> components

###Variables###
OSVersion=$(sw_vers | grep ProductVersion)
Label=com.bloomberg.<myapp>
LoggedInUser=$(/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }')
LoggedInUID=$(id -u $LoggedInUser)
LoggedInPID=$(ps -axj | awk "/^$LoggedInUser/ && /Dock.app/ {print $2;exit}")

###Paths###
<myapp>=/Library/Application Support/Bloomberg/<myapp>/<myapp>.app
<myapp>LaunchAgent=/Library/LaunchAgents/com.bloomberg.<myapp>.plist

###Functions###
#This section intentionally left blank

###Script Contents - Do Not Modify Below This Line###

case $OSVersion in

*10.[6-9]*)
if [[ -d "$<myapp>" ]]; then
echo "<myapp> is installed, unloading LaunchAgent and removing existing version"
Count=1
/bin/launchctl bsexec "$LoggedInPID" /usr/bin/sudo -iu "$LoggedInUser" "/bin/launchctl unload "$<myapp>LaunchAgent" &> /dev/null"
while [[ `echo $?` != 0 ]] && [[ "$Count" -lt 20 ]]
do
/bin/launchctl bsexec "$LoggedInPID" /usr/bin/sudo -iu "$LoggedInUser" "/bin/launchctl unload "$<myapp>LaunchAgent" &> /dev/null"
((Count++))
done
if /usr/bin/sudo /bin/launchctl list "$Label" &> /dev/null; then
/usr/bin/sudo /bin/launchctl unload "$<myapp>LaunchAgent"
fi
/usr/bin/sudo rm -rf "$<myapp>"
/usr/bin/sudo rm -f "$<myapp>LaunchAgent"
echo "Existing <myapp> version has been removed"
else
echo "<myapp> is not installed, no preinstall actions taken"
fi
;;

*10.[10-11]*)
if [[ -d "$<myapp>" ]]; then
echo "<myapp> is installed, unloading LaunchAgent and removing existing version"
Count=1
/bin/launchctl asuser "$LoggedInUID" /usr/bin/sudo -iu "$LoggedInUser" "/bin/launchctl unload "$<myapp>LaunchAgent" &> /dev/null"
while [[ `echo $?` != 0 ]] && [[ "$Count" -lt 20 ]]
do
/bin/launchctl asuser "$LoggedInUID" /usr/bin/sudo -iu "$LoggedInUser" "/bin/launchctl unload "$<myapp>LaunchAgent" &> /dev/null"
((Count++))
done
if /usr/bin/sudo /bin/launchctl list "$Label" &> /dev/null; then
/usr/bin/sudo /bin/launchctl unload "$<myapp>LaunchAgent"
fi
/usr/bin/sudo rm -rf "$<myapp>"
/usr/bin/sudo rm -f "$<myapp>LaunchAgent"
echo "Existing <myapp> version has been removed"
else
echo "<myapp> is not installed, no preinstall actions taken"
fi
;;

esac