Policies triggered at login?

DanJ_LRSFC
Contributor III

Is there any particular reason that would cause policies triggered at login to be so unreliable?

I have a login script which needs to run every time a user logs in. The actual outcome can be one of the following:
- The script runs perfectly
- There is a delay, but once the script gets started it runs perfectly
- Only parts of the script seem to get executed
- The script doesn't run at all and has to be manually triggered by the user from Self-Service

What causes this? How do I troubleshoot this? It's not due to the age of the Mac because we see this behaviour even on brand new Macs.

This seems to have been a problem ever since we started using the Jamf system - we're currently on version 10.6.0 and it still happens.

Alternatively if the login trigger can't be fixed, is there an alternative way to run a script at login while still having it centrally stored and managed in the Scripts area of the Jamf system? I don't want it to have to be a file that I have to deploy out every time I need to make a change.

I'm happy to post the script if that's needed, but it is quite long so I didn't want to spam everyone with a massive wall of text in the opening post.

Thanks,
Dan Jackson (Senior ITServices Technician)
Long Road Sixth Form College
Cambridge, UK.

1 ACCEPTED SOLUTION

DanJ_LRSFC
Contributor III

Expanding on my idea from yesterday, here's what I've done:

/Library/LaunchDaemons/uk.ac.longroad.SetUpLoginScript.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>uk.ac.longroad.SetUpLoginScript</string>
        <key>Program</key>
        <string>/Library/Scripts/SetUpLoginScript.sh</string>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

/Library/Scripts/SetUpLoginScript.sh:

#!/bin/sh

# Wait for network
. /etc/rc.common

CheckForNetwork

while [ "${NETWORKUP}" != "-YES-" ]
do
        sleep 2
        NETWORKUP=
        CheckForNetwork
done

# API username and password
user="YOUR API USERNAME HERE"
pass="YOUR API USER PASSWORD HERE"
scriptid="ID NUMBER FOR YOUR DESIRED SCRIPT HERE"

# Grab the script from the JSS using the API
response=$(/usr/bin/curl https://YOUR-JSS-SERVER-HERE.com/JSSResource/scripts/id/$scriptid --user "$user:$pass")
# Output it to /Library/Scripts/LongRoadLogin.sh
echo $response | /usr/bin/awk -F'<script_contents_encoded>|</script_contents_encoded>' '{print $2}' | /usr/bin/base64 --decode -o /Library/Scripts/LongRoadLogin.sh
# Ensure ownership and permissions are set correctly
chown root:wheel /Library/Scripts/LongRoadLogin.sh
chmod 755 /Library/Scripts/LongRoadLogin.sh

/Library/LaunchAgents/uk.ac.longroad.LongRoadLogin.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>uk.ac.longroad.LongRoadLogin</string>
        <key>Program</key>
        <string>/Library/Scripts/LongRoadLogin.sh</string>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

And /Library/Scripts/LongRoadLogin.sh is pretty much as seen earlier in this thread, but with one important change: I removed the sudo -u $loggedInUser from the mount command as it's already running in the user context.

View solution in original post

10 REPLIES 10

allanp81
Valued Contributor

@DanJ_LRSFC Post your policy config and the script and we can help to resolve the issue.

Ecco_Luke
Contributor II

I know we don't use them at our place due to their lack of reliability. Shame as well, because I had a policy recently that could have been ideally triggered at log-in rather than per user check-in.

millersc
Valued Contributor

Its been an ongoing problem. Some have moved to using outset for login needs. outset

Hugonaut
Valued Contributor II

A failproof method I've been using is as follows.

  1. Make a policy for each of the scripts you want to run. Then for trigger of each policy, set it to custom and give each policy a custom event name & set execution frequency to ongoing.

  2. Create an applescript and export it as a run only application. Make this file hidden or place it in a hidden directory.

-- Set Admin/Sudo Privvies
set UNAME to "sudo user"
set PASSW to "password"

try
    do shell script "sudo /usr/local/bin/jamf policy -event ScriptPolicy1" user name UNAME password PASSW with administrator privileges
end try

try
    do shell script "sudo /usr/local/bin/jamf policy -event ScriptPolicy2" user name UNAME password PASSW with administrator privileges
end try

try
    do shell script "sudo /usr/local/bin/jamf policy -event ScriptPolicy3" user name UNAME password PASSW with administrator privileges
end try

try
    do shell script "sudo /usr/local/bin/jamf policy -event ScriptPolicy4" user name UNAME password PASSW with administrator privileges
end try

3. Create a shell script that launches the applescript application.

#!/bin/sh

open -a '/Path/To/Startup/Hidden/AppleScript.app'

4. Create a launchagent that calls on the shell script (This way when the user logs in, it starts)

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> 
<plist version="1.0">
<dict> 
     <key>Label</key>
          <string>com.example.org</string>
     <key>Program</key>
          <string>/Path/To/Startup/Hidden/ShellScript.sh</string> 
     <key>RunAtLoad</key> 
     <true/> 
</dict> 
</plist>

Designated User Logs In, launchagent runs -> shell script -> applescript app -> designated policies run

I like using a shell script in between the plist & applescript applet as a buffer in the event i need to make some on the fly changes but the shell script isn't absolutely necessary, you can always just launch the applescript applet directly from the plist.

Hope this helps!

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month

mm2270
Legendary Contributor III

@Hugonaut are you certain the method you outlined is working for you? Because you mention using a LaunchAgent, but agents run as the user, and LaunchDaemons run as root. Since calling a script which in turn would run Jamf policies requires root or sudo, you'd need to use a LaunchDaemon. But that presents an issue since Daemons can and do run when no-one is logged in, in fact they start at bootup unless the plist specifies waiting for certain events, and since the purpose of this would be to run these policies at login, I'm not sure how you've been using that method effectively.

DanJ_LRSFC
Contributor III

@allanp81 here's my script:

#!/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"

# New shiny DEPNotify application!
echo "Command: MainTitle: Please wait while you are logged in." > /var/tmp/depnotify.log
echo "Command: MainText: Login in progress." >> /var/tmp/depnotify.log
echo "Command: DeterminateOff" >> /var/tmp/depnotify.log
echo "Status: Preparing" >> /var/tmp/depnotify.log
sleep 1
/Applications/Utilities/DEPNotify.app/Contents/MacOS/DEPNotify -fullScreen &
pid=$(pgrep DEPNotify)
while [ "${pid}" == "" ]
do
    sleep 1
    pid=$(pgrep DEPNotify)
done
echo "Status: Checking this Mac is bound to Active Directory" >> /var/tmp/depnotify.log
checkAD=`/usr/bin/dscl localhost -list . | grep "Active Directory"`
if [ "${checkAD}" != "Active Directory" ]
then
    # Mac is not bound to Active Directory
    echo "Status: This Mac is not bound to Active Directory" >> /var/tmp/depnotify.log
    sleep 2
    echo "Command: Quit" >> /var/tmp/depnotify.log
    exit 2
fi
echo "Status: Checking if user account is an Active Directory account" >> /var/tmp/depnotify.log
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
    echo "Status: User account is a local account" >> /var/tmp/depnotify.log
    ADAccount="false"
    if [ "$loggedInUser" == "student" ]
    then
        isStudent="true"
    fi
    if [ "$loggedInUser" == "yellow" ]
    then
        isStudent="true"
    fi
    if [ "$loggedInUser" == "blue" ]
    then
        isStudent="true"
    fi
fi
if [ "$ADAccount" == "true" ]
then
    # Active Directory account
    echo "Status: User account is an Active Directory account" >> /var/tmp/depnotify.log
    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'`
    echo "smbHome is $smbHome"
    echo "Status: Mounting user home directory at /Users/$loggedInUser/Documents" >> /var/tmp/depnotify.log
    sudo -u $loggedInUser /sbin/mount -t smbfs "$smbHome" "/Users/$loggedInUser/Documents"
    sleep 1
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" ]
    # add new dockutil versions here
    if [ -e "/Library/Scripts/dockutil.2.0.4.py" ]
    then
        echo "dockutil 2.0.4"
        dockUtilPath="/Library/Scripts/dockutil.2.0.4.py"
    fi
    if [ -e "/Library/Scripts/dockutil.2.0.5.py" ]
    then
        echo "dockutil 2.0.5"
        dockUtilPath="/Library/Scripts/dockutil.2.0.5.py"
    fi
    userPath="/Users/$loggedInUser"
    duNoRestart="--no-restart"
    duAdd="--add"
    duSectionApps="--section apps"
    duSectionOthers="--section others"
    if [ -d "/Applications/Adobe Photoshop CC 2015/Adobe Photoshop CC 2015.app" ]
    then
        photoshopPath="/Applications/Adobe Photoshop CC 2015/Adobe Photoshop CC 2015.app"
    elif [ -d "/Applications/Adobe Photoshop CC 2015.5/Adobe Photoshop CC 2015.5.app" ]
    then
        photoshopPath="/Applications/Adobe Photoshop CC 2015.5/Adobe Photoshop CC 2015.5.app"
    elif [ -d "/Applications/Adobe Photoshop CC 2017/Adobe Photoshop CC 2017.app" ]
    then
        photoshopPath="/Applications/Adobe Photoshop CC 2017/Adobe Photoshop CC 2017.app"
    fi
    if [ -d "/Applications/Adobe Bridge CC/Adobe Bridge CC.app" ]
    then
        bridgePath="/Applications/Adobe Bridge CC/Adobe Bridge CC.app"
    elif [ -d "/Applications/Adobe Bridge CC 2015/Adobe Bridge CC 2015.app" ]
    then
        bridgePath="/Applications/Adobe Bridge CC 2015/Adobe Bridge CC 2015.app"
    elif [ -d "/Applications/Adobe Bridge CC 2017/Adobe Bridge CC 2017.app" ]
    then
        bridgePath="/Applications/Adobe Bridge CC 2017/Adobe Bridge CC 2017.app"
    fi
    if [ -d "/Applications/Adobe Illustrator CC 2015/Adobe Illustrator.app" ]
    then
        illustratorPath="/Applications/Adobe Illustrator CC 2015/Adobe Illustrator.app"
    elif [ -d "/Applications/Adobe Illustrator CC 2015.3/Adobe Illustrator.app" ]
    then
        illustratorPath="/Applications/Adobe Illustrator CC 2015.3/Adobe Illustrator.app"
    elif [ -d "/Applications/Adobe Illustrator CC 2017/Adobe Illustrator.app" ]
    then
        illustratorPath="/Applications/Adobe Illustrator CC 2017/Adobe Illustrator.app"
    fi
    if [ -d "/Applications/Adobe After Effects CC 2015/Adobe After Effects CC 2015.app" ]
    then
        aftereffectsPath="/Applications/Adobe After Effects CC 2015/Adobe After Effects CC 2015.app"
    elif [ -d "/Applications/Adobe After Effects CC 2015.3/Adobe After Effects CC 2015.app" ]
    then
        aftereffectsPath="/Applications/Adobe After Effects CC 2015.3/Adobe After Effects CC 2015.app"
    elif [ -d "/Applications/Adobe After Effects CC 2017/Adobe After Effects CC 2017.app" ]
    then
        aftereffectsPath="/Applications/Adobe After Effects CC 2017/Adobe After Effects CC 2017.app"
    fi
    if [ -d "/Applications/Adobe Premiere Pro CC 2015/Adobe Premiere Pro CC 2015.app" ]
    then
        premierePath="/Applications/Adobe Premiere Pro CC 2015/Adobe Premiere Pro CC 2015.app"
    elif [ -d "/Applications/Adobe Premiere Pro CC 2015.3/Adobe Premiere Pro CC 2015.app" ]
    then
        premierePath="/Applications/Adobe Premiere Pro CC 2015.3/Adobe Premiere Pro CC 2015.app"
    elif [ -d "/Applications/Adobe Premiere Pro CC 2017/Adobe Premiere Pro CC 2017.app" ]
    then
        premierePath="/Applications/Adobe Premiere Pro CC 2017/Adobe Premiere Pro CC 2017.app"
    fi
    if [ -d "/Applications/Adobe Audition CC 2015/Adobe Audition CC 2015.app" ]
    then
        auditionPath="/Applications/Adobe Audition CC 2015/Adobe Audition CC 2015.app"
    elif [ -d "/Applications/Adobe Audition CC 2015.2/Adobe Audition CC 2015.app" ]
    then
        auditionPath="/Applications/Adobe Audition CC 2015.2/Adobe Audition CC 2015.app"
    elif [ -d "/Applications/Adobe Audition CC 2017/Adobe Audition CC 2017.app" ]
    then
        auditionPath="/Applications/Adobe Audition CC 2017/Adobe Audition CC 2017.app"
    fi
    if [ -d "/Applications/Microsoft Word.app" ]
    then
        wordPath="/Applications/Microsoft Word.app"
    elif [ -d "/Applications/Microsoft Office 2011/Microsoft Word.app" ]
    then
        wordPath="/Applications/Microsoft Office 2011/Microsoft Word.app"
    fi
    if [ -d "/Applications/Adobe InDesign CC 2017/Adobe InDesign CC 2017.app" ]
    then
        indesignPath="/Applications/Adobe InDesign CC 2017/Adobe InDesign CC 2017.app"
    elif [ -d "/Applications/Adobe InDesign CC 2015/Adobe InDesign CC 2015.app" ]
    then
        indesignPath="/Applications/Adobe InDesign CC 2015/Adobe InDesign CC 2015.app"
    fi
    if [ -d "/Applications/Autodesk/maya2018/Maya.app" ]
    then
        mayaPath="/Applications/Autodesk/maya2018/Maya.app"
    elif [ -d "/Applications/Autodesk/maya2017/Maya.app" ]
    then
        mayaPath="/Applications/Autodesk/maya2017/Maya.app"
    elif [ -d "/Applications/Autodesk/maya2016/Maya.app" ]
    then
        mayaPath="/Applications/Autodesk/maya2016/Maya.app"
    fi
    if [ -d "/Applications/Autodesk/Mudbox2018/Mudbox.app" ]
    then
        mudboxPath="/Applications/Autodesk/Mudbox2018/Mudbox.app"
    elif [ -d "/Applications/Autodesk/Mudbox2017/Mudbox.app" ]
    then
        mudboxPath="/Applications/Autodesk/Mudbox2017/Mudbox.app"
    elif [ -d "/Applications/Autodesk/Mudbox2016/Mudbox.app" ]
    then
        mudboxPath="/Applications/Autodesk/Mudbox2016/Mudbox.app"
    fi
    if [ -d "/Applications/Microsoft Excel.app" ]
    then
        excelPath="/Applications/Microsoft Excel.app"
    elif [ -d "/Applications/Microsoft Office 2011/Microsoft Excel.app" ]
    then
        excelPath="/Applications/Microsoft Office 2011/Microsoft Excel.app"
    fi
    if [ -d "/Applications/Microsoft PowerPoint.app" ]
    then
        powerpointPath="/Applications/Microsoft PowerPoint.app"
    elif [ -d "/Applications/Microsoft Office 2011/Microsoft PowerPoint.app" ]
    then
        powerpointPath="/Applications/Microsoft Office 2011/Microsoft PowerPoint.app"
    fi
    echo "Status: Setting up the Dock" >> /var/tmp/depnotify.log
    echo "Removing all Dock icons"
    $dockUtilPath $duNoRestart --remove all $userPath
    sleep 1
    echo "Adding new Dock icons"
    case "$loggedInUser" in
        "blue"|"yellow")
            $dockUtilPath $duNoRestart $duAdd "/Applications/Google Chrome.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/Keynote.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "$photoshopPath" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "$premierePath" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/Adobe Lightroom/Adobe Lightroom.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "$auditionPath" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/GarageBand.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "$wordPath" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/TextEdit.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/Photos.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/Font Book.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/Image Capture.app" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/Self Service.app" $duSectionApps $userPath
            ;;
        *)
            $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
            echo "Adding Bridge: $bridgePath"
            $dockUtilPath $duNoRestart $duAdd "$bridgePath" $duSectionApps $userPath
            echo "Adding Illustrator: $illustratorPath"
            $dockUtilPath $duNoRestart $duAdd "$illustratorPath" $duSectionApps $userPath
            echo "Adding Photoshop: $photoshopPath"
            $dockUtilPath $duNoRestart $duAdd "$photoshopPath" $duSectionApps $userPath
            echo "Adding After Effects: $aftereffectsPath"
            $dockUtilPath $duNoRestart $duAdd "$aftereffectsPath" $duSectionApps $userPath
            echo "Adding Premiere: $premierePath"
            $dockUtilPath $duNoRestart $duAdd "$premierePath" $duSectionApps $userPath
            echo "Adding InDesign: $indesignPath"
            $dockUtilPath $duNoRestart $duAdd "$indesignPath" $duSectionApps $userPath
            if [ -d "/Applications/Autodesk/AutoCAD 2015" ]
            then
                $dockUtilPath $duNoRestart $duAdd "/Applications/Autodesk/AutoCAD 2015/AutoCad 2015.app" $duSectionApps $userPath
            fi
            echo "Adding Maya: $mayaPath"
            $dockUtilPath $duNoRestart $duAdd "$mayaPath" $duSectionApps $userPath
            echo "Adding Mudbox: $mudboxPath"
            $dockUtilPath $duNoRestart $duAdd "$mudboxPath" $duSectionApps $userPath
            echo "Adding Microsoft Word: $wordPath"
            $dockUtilPath $duNoRestart $duAdd "$wordPath" $duSectionApps $userPath
            echo "Adding Microsoft Excel: $excelPath"
            $dockUtilPath $duNoRestart $duAdd "$excelPath" $duSectionApps $userPath
            echo "Adding Microsoft PowerPoint: $powerpointPath"
            $dockUtilPath $duNoRestart $duAdd "$powerpointPath" $duSectionApps $userPath
            $dockUtilPath $duNoRestart $duAdd "/Applications/PCClient.app" --label "PaperCut Client" $duSectionApps $userPath
            if [ -d "/Applications/Epson Software/EPSON Scan.app" ]
            then
                $dockUtilPath $duNoRestart $duAdd "/Applications/Epson Software/EPSON Scan.app" --label "EPSON Scan" $duSectionApps $userPath
            fi
            ;;
    esac
    echo "Adding Documents folder and restarting Dock"
    $dockUtilPath $duAdd "$userPath/Documents" --label $loggedInUser $duSectionOthers $userPath
    echo "Resetting wallpaper"
    echo "Status: Resetting wallpaper" >> /var/tmp/depnotify.log
    case "$loggedInUser" in
        yellow) osascript -e 'tell application "System Events" to set picture of every desktop to POSIX file "/Library/Desktop Pictures/L2 YELLOW DESKTOP IMAGE.png"'
                echo "Reset wallpaper to yellow"
                ;;
        blue)   osascript -e 'tell application "System Events" to set picture of every desktop to POSIX file "/Library/Desktop Pictures/L2 BLUE DESKTOP IMAGE.png"'
                echo "Reset wallpaper to blue"
                ;;
        *)      osascript -e 'tell application "System Events" to set picture of every desktop to POSIX file "/Library/Desktop Pictures/lrsfc_spring2016_17_wallpaper.jpg"'
                echo "Reset wallpaper to standard"
                ;;
    esac
fi
if [ -d "/Applications/PCClient.app" ]
then
    echo "Loading PaperCut client..."
    echo "Status: Loading PaperCut client" >> /var/tmp/depnotify.log
    sudo -u $loggedInUser -b /Applications/PCClient.app/Contents/Resources/pc-client-mac.command
fi
echo "Status: Login complete" >> /var/tmp/depnotify.log
sleep 2
echo "Command: Quit" >> /var/tmp/depnotify.log
sleep 1
rm -rf /var/tmp/depnotify.log
exit 0

The policy is just set to trigger on Login, on an Ongoing basis, but is currently scoped to a smart group called "SW - Has DEPNotify" (all of the affected Macs are in this smart group). To be fair the problem happened with the previous iteration of the script that used jamfHelper and was scoped to all Macs anyway.

Hugonaut
Valued Contributor II

@mm2270

Yes, Thanks for pointing that out. I forgot to add the applescript step! Updated my post with it

________________
Looking for a Jamf Managed Service Provider? Look no further than Rocketman
________________


Virtual MacAdmins Monthly Meetup - First Friday, Every Month

DanJ_LRSFC
Contributor III

I had some ideas about different ways this could be achieved, however I have some more questions to fill in the blanks.

With regard to a LaunchDaemon script, is the network interface guaranteed to be up by the time that's launched, or is there a need to wait for it if network operations are needed?

I thought of having a LaunchDaemon that uses the Jamf Classic API to download the script and if there's no local file or if the local file in /Library/Scripts differs, replace that file. Not quite sure how to do the difference checking and file outputting, looks like the API can output XML or JSON but I'm not sure how to get stuff out of those within a script.

Then the local file could be run using a LaunchAgent (I don't think there's anything in my script that actually requires root? the sudo -u $loggedInUser could presumably be removed as mount should work without providing credentials if run in the regular user context anyway?)

DanJ_LRSFC
Contributor III

Expanding on my idea from yesterday, here's what I've done:

/Library/LaunchDaemons/uk.ac.longroad.SetUpLoginScript.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>uk.ac.longroad.SetUpLoginScript</string>
        <key>Program</key>
        <string>/Library/Scripts/SetUpLoginScript.sh</string>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

/Library/Scripts/SetUpLoginScript.sh:

#!/bin/sh

# Wait for network
. /etc/rc.common

CheckForNetwork

while [ "${NETWORKUP}" != "-YES-" ]
do
        sleep 2
        NETWORKUP=
        CheckForNetwork
done

# API username and password
user="YOUR API USERNAME HERE"
pass="YOUR API USER PASSWORD HERE"
scriptid="ID NUMBER FOR YOUR DESIRED SCRIPT HERE"

# Grab the script from the JSS using the API
response=$(/usr/bin/curl https://YOUR-JSS-SERVER-HERE.com/JSSResource/scripts/id/$scriptid --user "$user:$pass")
# Output it to /Library/Scripts/LongRoadLogin.sh
echo $response | /usr/bin/awk -F'<script_contents_encoded>|</script_contents_encoded>' '{print $2}' | /usr/bin/base64 --decode -o /Library/Scripts/LongRoadLogin.sh
# Ensure ownership and permissions are set correctly
chown root:wheel /Library/Scripts/LongRoadLogin.sh
chmod 755 /Library/Scripts/LongRoadLogin.sh

/Library/LaunchAgents/uk.ac.longroad.LongRoadLogin.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>Label</key>
        <string>uk.ac.longroad.LongRoadLogin</string>
        <key>Program</key>
        <string>/Library/Scripts/LongRoadLogin.sh</string>
        <key>RunAtLoad</key>
        <true/>
    </dict>
</plist>

And /Library/Scripts/LongRoadLogin.sh is pretty much as seen earlier in this thread, but with one important change: I removed the sudo -u $loggedInUser from the mount command as it's already running in the user context.

marklamont
Contributor III

we had loads of issues with at logon polices as logon hooks are flakey, using https://github.com/execriez/ConsoleUserWarden this sorted it all out..