Posted on 06-27-2016 03:43 AM
We've got a GUI AppleScript which we want to run at login as the user who is logging in. It has to be saved as an .app as the AppleScript progress bar functionality does not work otherwise.
Currently we've got a policy set to trigger on login with a "Files and Processes" payload with the command open "/Library/Scripts/LongRoadInit.app"
however this seems to be somewhat unreliable as we've had a number of reports of this not getting run.
We're on OS X 10.10 Yosemite and Casper Suite 9.92.
Here's the script:
set progress description to "Long Road Mac login process"
set progress additional description to "Preparing, please wait..."
set progress total steps to -1
delay 2
set progress total steps to 7
set progress completed steps to 0
set progress additional description to "Checking if Mac is bound to Active Directory"
set checkAD to do shell script "(/usr/bin/dscl localhost -list . | grep " & (quoted form of "Active Directory") & ") || echo Not found"
if checkAD contains "Active Directory" then
-- Mac is bound to Active Directory
set thisUser to short user name of (system info)
set progress completed steps to 1
set progress additional description to "Looking up user's home directory"
set ADAccount to true
set isStudent to false
try
set smbHomeRaw to do shell script "/usr/bin/dscl localhost -read /Active\ Directory/COLLEGE/All\ Domains/Users/" & thisUser & " SMBHome 2>&1"
on error errMsg
set progress completed steps to -1
set progress additional description to "Not Active Directory account"
delay 2
set ADAccount to false
if thisUser is equal to "student" then
set isStudent to true
end if
end try
if ADAccount then
set studentGroups to do shell script "id " & thisUser & " | grep " & (quoted form of "All Students Security\|Examinees")
if studentGroups as string is not equal to "" then
set isStudent to true
end if
set AppleScript's text item delimiters to " "
set the item_list to every text item of smbHomeRaw
set the new_item to text item 2 of the item_list
set AppleScript's text item delimiters to "\"
set the new_item_list to every text item of new_item
set AppleScript's text item delimiters to "/"
set smbHome to the new_item_list as string
if smbHome does not contain thisUser then
set myErrorMessage to "Error! Home directory not found!"
display alert myErrorMessage buttons {"OK"} as critical
return
end if
delay 1
set progress completed steps to 2
set progress additional description to "Mounting user's home directory at /Users/" & thisUser & "/Documents"
do shell script "/sbin/mount -t smbfs " & smbHome & " /Users/" & thisUser & "/Documents"
if (list disks) does not contain thisUser then
set myErrorMessage to "Error! Could not mount home directory!"
display alert myErrorMessage buttons {"OK"} as critical
return
end if
end if
else
set progress completed steps to -1
set progress additional description to "Not bound to Active Directory"
delay 10
return
end if
if isStudent then
set progress completed steps to 3
set progress additional description to "Configuring Dock icons"
set dockUtilPath to "/Library/Scripts/LongRoadInit.app/Contents/Resources/Scripts/dockutil.py"
set userPath to "/Users/" & thisUser
set duNoRestart to " --no-restart"
set duAdd to " --add "
set duSectionApps to " --section apps "
set duSectionOthers to " --section others "
do shell script dockUtilPath & duNoRestart & " --remove all " & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Google Chrome.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/VLC.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Image Capture.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Adobe Bridge CS6/Adobe Bridge CS6.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Adobe Illustrator CS6/Adobe Illustrator.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Adobe Photoshop CS6/Adobe Photoshop CS6.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Adobe After Effects CS6/Adobe After Effects CS6.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Adobe Premiere Pro CS6/Adobe Premiere Pro CS6.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Adobe InDesign CS6/Adobe InDesign CS6.app") & duSectionApps & userPath
set scriptCommand to "if [[ -d " & (quoted form of "/Applications/Autodesk/AutoCAD 2015") & " ]];then " & dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Autodesk/AutoCAD 2015/AutoCad 2015.app") & duSectionApps & userPath & ";fi"
do shell script scriptCommand
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Autodesk/maya2016/Maya.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Autodesk/Mudbox2016/Mudbox.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Microsoft Office 2011/Microsoft Word.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Microsoft Office 2011/Microsoft Excel.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/Microsoft Office 2011/Microsoft PowerPoint.app") & duSectionApps & userPath
do shell script dockUtilPath & duNoRestart & duAdd & (quoted form of "/Applications/PCClient.app") & duSectionApps & userPath
delay 1
set progress completed steps to 4
set progress additional description to "Restarting Dock"
do shell script dockUtilPath & duAdd & (quoted form of ("/Users/" & thisUser & "/Documents")) & " --label " & (quoted form of thisUser) & duSectionOthers & userPath
delay 1
set progress completed steps to 5
set progress additional description to "Resetting wallpaper"
tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/lrsfc_lrcstudents_wallpaper_mac.jpg"
delay 1
end if
set progress completed steps to 6
set progress additional description to "Loading PaperCut client"
delay 1
tell application "System Events"
if exists file "/Applications/PCClient.app" then
do shell script "open -g /Applications/PCClient.app"
end if
end tell
delay 1
set progress completed steps to 7
set progress additional description to "Login complete, you may now start using the Mac"
delay 2
Posted on 06-27-2016 05:22 AM
Hi,
The login trigger still uses loginhooks (I believe) which runs as root and too early for AppleScripts.
Have you tried triggering it with a LaunchAgent instead?
Last resort would be to add something to the users login items either with another script or a profile.
Posted on 06-27-2016 05:39 AM
LaunchAgent has been working for use with an AppleScript that mounts User shares. You could also look into outset. Been testing that with Dockutil.
Posted on 06-27-2016 05:46 AM
@davidacland We used to run it with a LaunchAgent, however we found that there was often a considerable delay between the user logging in and the script running.
Is there another way we can display either progress or status messages on the screen for the user while our script is executing? That way we could remove the AppleScript requirement.
With regard to a script running as root, is there a way using sudo to run commands in the logged in user's context? Specifically the mount command so that we don't need to know the user's password in order to connect to their network home folder.
Thanks,
Dan Jackson (Lead ITServices Technician)
Long Road Sixth Form College
Cambridge, UK.
Posted on 06-27-2016 05:48 AM
You could try using jamfhelper to display a message while it is running.
Posted on 06-27-2016 06:06 AM
@davidacland The full screen mode of that would be great if it wasn't modal (i.e. allowed my script to continue in the background) or respected the timeout option (it doesn't seem to). Or am I using it wrong?
Ideally rather than a static message I'd like to be able to change what is displayed as the script goes along, so that the user knows something is happening.
EDIT: looks like something like this will work:
#!/bin/bash
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Login" -description "Preparing login, please wait..." &
JAMF_PID=$!
# do stuff
kill $JAMF_PID
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Login" -description "Some other message..." &
JAMF_PID=$!
# do more stuff
kill $JAMF_PID
Posted on 06-27-2016 02:19 PM
One thing you can do is use two overlaying Jamfhelper windows that read the last line of a file, then you can just have other processes append stuff to the file to update the message.
This is the loop I have as part of a post restart status message script, it has no exit clause as the machine restarts again, but it might give you some ideas. basically the new window appears over the previous one and the previous one times out in the background. It works reasonably well but you kind of have to cleanse the messages etc... so they are similar lengths.
while :
do
Status_Mark=$(date +"%H:%M:%S")
Status_Message=$(tail -n1 /Library/Logs/JAMF/ImagingScripts.log)
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -title "Please do not use or power off" -heading "STATUS ${Status_Mark}" -description "${Status_Message}" -lockHUD -timeout 10 -windowType utility -windowPosition ll &
sleep 9
done
Posted on 06-28-2016 06:44 AM
So here's what I've got so far.
EDIT: To mitigate the flashing, I found if I stack up all the messages in reverse order at the start and then kill them off one by one, that achieves a message change without the flash.
#!/bin/bash
# Get logged in user, the official Apple-approved way
loggedInUser=`python -c 'from SystemConfiguration import SCDynamicStoreCopyConsoleUser; import sys; username = (SCDynamicStoreCopyConsoleUser(None, None, None) or [None])[0]; username = [username,""][username in [u"loginwindow", None, u""]]; sys.stdout.write(username + "
");'`
echo "Logged in user is $loggedInUser"
# Stack jamfHelper windows up to start with, kill processes when you want to change message
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Login complete, you may now start using the Mac." &
PID_LOGINCOMPLETE=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Loading PaperCut client..." &
PID_PAPERCUT=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Resetting wallpaper..." &
PID_WALLPAPER=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Restarting Dock..." &
PID_DOCK_RESTART=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Configuring Dock icons..." &
PID_DOCK_CONFIG=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Mounting user's home directory at /Users/$loggedInUser/Documents..." &
PID_MOUNT=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Looking up user's home directory..." &
PID_LOOKUP=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "This Mac is not bound to Active Directory." &
PID_NOAD=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Checking if Mac is bound to Active Directory..." &
PID_CHECKAD=$!
/Library/Application Support/JAMF/bin/jamfHelper.app/Contents/MacOS/jamfHelper -windowType fs -heading "Long Road Mac Login" -description "Preparing login, please wait..." &
PID_PREPARING=$!
sleep 2
kill $PID_PREPARING
wait $PID_PREPARING 2> /dev/null
checkAD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`
if [ "${checkAD}" != "Active Directory" ]
then
# Mac is not bound to Active Directory
kill $PID_CHECKAD
wait $PID_CHECKAD 2> /dev/null
sleep 2
killall jamfHelper
exit 2
fi
kill $PID_NOAD
wait $PID_NOAD 2> /dev/null
kill $PID_CHECKAD
wait $PID_CHECKAD 2> /dev/null
ADAccount="true"
isStudent="false"
smbHomeRaw=`/usr/bin/dscl localhost -read "/Active Directory/COLLEGE/All Domains/Users/$loggedInUser" SMBHome 2>&1`
if [ $? != 0 ]
then
# Not an Active Directory account
ADAccount="false"
if [ "$loggedInUser" == "student" ]
then
isStudent="true"
fi
fi
if [ "$ADAccount" == "true" ]
then
# Active Directory account
studentGroups=`id $loggedInUser | grep "All Students Security|Examinees"`
if [ "$studentGroups" != "" ]
then
isStudent="true"
fi
# Munge SMB Home into correct format
smbHome="smb:"
smbHome+=`echo $smbHomeRaw | awk '{ print $2 }' | sed 's.\\./.g'`
kill $PID_LOOKUP
wait $PID_LOOKUP 2> /dev/null
echo "smbHome is $smbHome"
sudo -u $loggedInUser /sbin/mount -t smbfs "$smbHome" "/Users/$loggedInUser/Documents"
fi
if [ `pgrep jamfHelper | grep $PID_LOOKUP` ]
then
kill $PID_LOOKUP
wait $PID_LOOKUP 2> /dev/null
fi
if [ "$isStudent" == "true" ]
then
# do stuff if the account is a student
# dock icons
# wallpaper
MAC_MAJOR_VERSION=`sw_vers -productVersion | awk -F '.' '{print $1 "." $2}'`
echo "Checking OS version for dockutil: $MAC_MAJOR_VERSION"
if [ "$MAC_MAJOR_VERSION" == "10.8" ]
then
echo "dockutil 1.1.4"
dockUtilPath="/Library/Scripts/dockutil.1.1.4.py"
else
echo "dockutil 2.0.4"
dockUtilPath="/Library/Scripts/dockutil.2.0.4.py"
fi
userPath="/Users/$loggedInUser"
duNoRestart="--no-restart"
duAdd="--add"
duSectionApps="--section apps"
duSectionOthers="--section others"
kill $PID_MOUNT
wait $PID_MOUNT 2> /dev/null
echo "Removing all Dock icons"
$dockUtilPath $duNoRestart --remove all $userPath
sleep 2
echo "Adding new Dock icons"
$dockUtilPath $duNoRestart $duAdd "/Applications/Google Chrome.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/VLC.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/Image Capture.app" $duSectionApps $userPath
#$dockUtilPath $duNoRestart $duAdd "/Applications/Adobe Bridge CS6/Adobe Bridge CS6.app" $duSectionApps $userPath
#$dockUtilPath $duNoRestart $duAdd "/Applications/Adobe Illustrator CS6/Adobe Illustrator.app" $duSectionApps $userPath
#$dockUtilPath $duNoRestart $duAdd "/Applications/Adobe Photoshop CS6/Adobe Photoshop CS6.app" $duSectionApps $userPath
#$dockUtilPath $duNoRestart $duAdd "/Applications/Adobe After Effects CS6/Adobe After Effects CS6.app" $duSectionApps $userPath
#$dockUtilPath $duNoRestart $duAdd "/Applications/Adobe Premiere Pro CS6/Adobe Premiere Pro CS6.app" $duSectionApps $userPath
#$dockUtilPath $duNoRestart $duAdd "/Applications/Adobe InDesign CS6/Adobe InDesign CS6.app" $duSectionApps $userPath
if [ -d "/Applications/Autodesk/AutoCAD 2015" ]
then
$dockUtilPath $duNoRestart $duAdd "/Applications/Autodesk/AutoCAD 2015/AutoCad 2015.app" $duSectionApps $userPath
fi
$dockUtilPath $duNoRestart $duAdd "/Applications/Autodesk/maya2016/Maya.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/Autodesk/Mudbox2016/Mudbox.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/Microsoft Office 2011/Microsoft Word.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/Microsoft Office 2011/Microsoft Excel.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/Microsoft Office 2011/Microsoft PowerPoint.app" $duSectionApps $userPath
$dockUtilPath $duNoRestart $duAdd "/Applications/PCClient.app" $duSectionApps $userPath
kill $PID_DOCK_CONFIG
wait $PID_DOCK_CONFIG 2> /dev/null
echo "Adding Documents folder and restarting Dock"
$dockUtilPath $duAdd "$userPath/Documents" --label $loggedInUser $duSectionOthers $userPath
kill $PID_DOCK_RESTART
wait $PID_DOCK_RESTART 2> /dev/null
echo "Resetting wallpaper"
osascript -e 'tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/lrsfc_lrcstudents_wallpaper_mac.jpg"'
fi
kill $PID_WALLPAPER
wait $PID_WALLPAPER 2> /dev/null
if [ `pgrep jamfHelper | grep $PID_MOUNT` ]
then
kill $PID_MOUNT
wait $PID_MOUNT 2> /dev/null
fi
if [ `pgrep jamfHelper | grep $PID_DOCK_CONFIG` ]
then
kill $PID_DOCK_CONFIG
wait $PID_DOCK_CONFIG 2> /dev/null
fi
if [ `pgrep jamfHelper | grep $PID_DOCK_RESTART` ]
then
kill $PID_DOCK_RESTART
wait $PID_DOCK_RESTART 2> /dev/null
fi
if [ -d "/Applications/PCClient.app" ]
then
open -g /Applications/PCClient.app
fi
kill $PID_PAPERCUT
wait $PID_PAPERCUT 2> /dev/null
sleep 2
kill $PID_LOGINCOMPLETE
wait $PID_LOGINCOMPLETE 2> /dev/null
exit 0
Posted on 06-28-2016 06:59 AM
I don't suppose there's any way to tell an existing/running jamfHelper process to change its message?
No there isn't. Its a static image and message per call. The only way to change it on the fly is to do similar to what you're doing. killing one and popping up another, repeatedly. This boils down to using jamfHelper for a purpose different than how JAMF intended it to be used really. Not that that's a bad thing, but its just the reality of the situation and something you need to live with for now, until or if JAMF beefs up jamfHelper's capabilities. I'm not sure that that's on their roadmap though.
Posted on 06-28-2016 07:51 AM
My next problem is, occasionally when I log in, this script doesn't run at all. How do I troubleshoot this? The logs in the policy don't shed any light on it. Is it just that the policy needs to be made available offline or something?
Posted on 06-28-2016 07:58 AM
You could set it to run Offline, but, and a lot of people get confused by this, there's a bit of a chicken and egg problem with offline cached policies. The policy must run at least once while the Mac logs in "online" or on a network that is connected to the JSS in order for it to be cached to the Mac to later run in offline mode. If you have Macs that have never run it before, booting up and logging in off the network, it won't run on them. Its not going to until some later time when the client logs in with an active network connection so it can run the Login policy trigger successfully.
This is one of the main reasons I almost never use the login trigger with policies. It may be OK in labs or with iMacs and Mac Pros that are typically using a wired Ethernet connection, but as we are about 99% laptops, so many of our Macs log in off the network, so our success rate in using a login trigger would be pretty dismal.
Outside of this, have you checked to make sure the execution frequency is set correctly? Is it set to run once per computer or on some other frequency?
Posted on 06-29-2016 05:19 AM
@mm2270 I am seeing this problem on my test Mac though, which is connected with a wired Ethernet connection.
I set the execution frequency to Ongoing as we want it to run every time any user logs on. I have not set any limitations or exclusions, but as this is just for testing purposes, the target is set to All Users and Specific Computers with my test Mac added in.
Posted on 07-13-2016 10:34 AM
@DanJ_LRSFC Could this script be triggered via a LaunchAgent instead?