Acceptable Use Policy Pop up

GabeShack
Valued Contributor III

Hey all,
I've been starting to play around with putting an acceptable use policy pop up during the login process. Unfortunately we cannot afford JAMF connect, and I don't love the Apple Policy Banner that displays each time the machine reboots. I'd rather have a pop up (maybe with JamfHelper) that states the AUP and then gives the option to accept it during the first login. Then at least I'd have a log file showing the policy ran and they clicked accept.

Anyone doing this sort of thing already so I don't have to build it from scratch?

Currently we are using DEP notify to do the naming of the computers and cannot have end users dealing with this step of the process, but I do know that depnotify has this feature as well.

I'm also aware of the enrollment customization piece, however since it cannot accomplish the naming of our computers, it's still not a good solution.

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools
1 ACCEPTED SOLUTION

GabeShack
Valued Contributor III

@Billski Thanks for this!
So far in my testing just running the @mm2270 script is working great with a few modifications. I'm having this script run after a few scripts I have happening during the users 1st login (opening various apps and pre-populating their user name/email addresses). I also added the marketing model name, and serial number to this as well. Since I only need this to run once per users computer, I have it run during that initial login, then keep the file there since the EA runs a cat of the text file at the next inventory update and then attaches it to the record. (If it doesn't find the file, it leaves the field blank). The EA then adds it to the JSS record in the Users and Location tab, which seems like a good enough place to look up that they signed off on this.

After trialing this out a few times, I think it will be perfect for newly imaged staff devices. I may push the policy to run the script out to staff who already have their computer too just to get everyone in compliance.

Thanks all for your help. Attached is my modified version if anyone else wants to use it.

#!/bin/bash

## Put full path to coocoaDialog here, wherever you deploy it to systems. Note the path all the way to the executable inside "MacOS"
CDPATH="/Users/Shared/cocoaDialogNew.app/Contents/MacOS/cocoaDialog"

## Capture the logged in user short name
loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

## Get the full user name from dscl, if applicable for your environment (may need adjustment; test this separately)
fullName=$( dscl . read /Users/$loggedInUser RealName | awk -F, '{getline; print $2$1}' | sed 's/^ *//' )

## Get the computer name
compName=$( scutil --get ComputerName )

## Get the computer Serial Number
serialNumber=$( ioreg -c IOPlatformExpertDevice -d 2 | awk -F" '/IOPlatformSerialNumber/{print $(NF-1)}' )

## Get the computer model
model=$(curl -s https://support-sp.apple.com/sp/product?cc=$(
  system_profiler SPHardwareDataType 
    | awk '/Serial/ {print $4}' 
    | cut -c 9-
) | sed 's|.*<configCode>(.*)</configCode>.*|1|')

## Path to EULA file with data on disk
eulaFILE="/private/var/eula_agreement"

## Edit this text below. Note that you may need to adjust the --height integer in the cocoaDialog call to accommodate longer text
MsgText="Below is Your Company's Acceptable Use Policy.

Please read it carefully, then check the "I agree to these terms" checkbox below, and finally click "OK".

Your AUP Here"

## Main script starts here

## See who's logged in. If its not "root" we aren't sitting at the login screen.
if [[ "$loggedInUser" != "root" ]]; then

    echo "A user is logged in"

    ## Check to see if a eula_agreement file is already on disk, just in case it ran already

    if [[ ! -e "$eulaFILE" ]]; then

        echo "No previous eula_agreement file found on disk. Continuing..."

        # Display the dialog. Notes:
        # 1. The "--value-required" flag forces them to check the checkbox before the dialog can be dismissed.
        # 2. If you want a custom icon, use --icon-file instead of --icon below and enter the full path to the icon file (icns, png, jpg, etc)
        # 3. Adjustment of the --width and --height integers may be necessary. Occasionally CD doesn't rescale correctly based on the text.    
        # 4. Enter a title after --title if you want the dialog to have one. Use "" to use a blank title

        EULADialog=$( "$CDPATH" checkbox --title "Acceptable Use Policy" --label "$MsgText" 
        --items "I agree to these terms" --button1 "   OK   " --value-required 
        --icon-file "/Library/Desktop Pictures/PPSLogo.jpg" info --width 800 --height 950 )

        ## Now detect the response.
        if [[ $( echo "$EULADialog" | awk 'NR>1{print $0}' ) == "1" ]]; then

            echo "The dialog exited with the Agree button checked"
            AgreeChecked="User Clicked I Agree"

## Export the settings to a file on disk that can be picked up by recon later

echo -e "EULA agreement status:

Username:   $loggedInUser
Full Name:  $fullName
Model:  $model
Computer Name:  $compName
Computer Serial:  $serialNumber
User Agreed?:   $AgreeChecked
Agreement Date: $(date +"%b %d, %Y, %T")" > "$eulaFILE"

            ## Run a recon to suck up the EULA file. You will need an Extension Attribute designed to capture the contents of this file.
#            echo "Gathering new inventory"
#            jamf recon

            ## If the recon was successful
#            if [[ "$?" == "0" ]]; then

                ## Now, clean up
                ## Unload the LaucnhDaemon that triggers the script
#                /bin/launchctl unload /Library/LaunchDaemons/com.nameoflaunchdamon.plist
                ## Delete the LaunchDaemon
#                /bin/rm -f "/Library/LaunchDaemon/com.nameoflaunchdaemon.plist"
                ## Delete the eula file
#                /bin/rm "$eulaFILE"
                ## Delete the script last
#                /bin/rm -f "$0"

            else

#                echo "Recon failed. Let's not delete anything until we can capture the file. Exit until next run..."
                exit 0

            fi

        else

            echo "Somehow the 'I agree' box wasn't checked. Exit until next run..."
            exit 0

        fi

#    else

#        echo "An existing eula_agreement file was found. Run recon (just in case) and then delete the file..."
#        jamf recon
#        /bin/rm "$eulaFILE"
#        exit 0

#    fi

else

    ## If the logged in user is root, the Mac is still sitting at the login window. Exit and wait until the next run
    echo "There is no logged in user. Exit until next run..."
    exit 0

fi

Also here is the Extension Attribute to gather the text file into the record:

#!/bin/sh
Result=$(cat /private/var/eula_agreement)
echo "<result>$Result</result>"

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

View solution in original post

14 REPLIES 14

Billski
New Contributor II

Hi there,

We use cocoaDialogue to display a custom EULA/Acceptable use policy to our users the first time they log in as described in this post by mm2270. We then attach the "agreed" EULA file that is created to the machines inventory via the API. Following this we use a python script to send a copy to the user via email.

Hope this helps,

Billy

GabeShack
Valued Contributor III

@Billski Thanks for this!
Any chance you could share the python script(redacted of course with any secure details).
Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

emily
Valued Contributor III
Valued Contributor III

Is there a reason you need a EULA to happen at the same time as a computer rename? You could have the renaming happen in the background on its own policy after login.

Another option is DEPNotify which has a EULA pop-up functionality and can support text field inputs. There’s a handy DEPNotify-Starter script designed to work with Jamf Pro that makes setting it up and using it pretty straightforward.

GabeShack
Valued Contributor III

Hey @emily ,
Thanks for the thoughts. No, in fact we don't want the EULA to happen during the enrollment/Computer naming, that we do with DEPNotify as noted above.
We do use DEPNotify, and I'm aware of this feature, but in the way we image and name our machines it would not work to happen at that stage, as the initial login to our admin user is done by techs, which then triggers DEPNotify. Once the DEPNotify script installs our base apps and items, it reboots with any and all system updates, then is ready for our final end users to login.

I'd want the EULA to happen during this next login. So ideally whatever EULA process we use would install during the DEPNotify script, and then run when the next user logs in.

I'm liking the idea posted above from @Billski and am hoping to get some more info from him with maybe a copy of his scripts to use as a template.

Thanks again for the reply!
Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

emily
Valued Contributor III
Valued Contributor III

@gshackney have you considered making your launch script/whatever for DEPNotify not run when your tech accounts are signed in? Seems a shame to not use that built-in functioning if you’re already using the app.

GabeShack
Valued Contributor III

We would much rather prompt the techs to name the computers in the way we like before we move on to having the end user login, and there is too much room for error with end users naming their own computers that we'd rather have the techs do the initial step. After that though, yes we could make it so DEPNotify runs again just with the EULA piece, but I do like the script referenced above since that could be managed separately and also could send us a hard copy.

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

Of course all of our issues with DEPNotify could be resolved if JAMF would just put in a way to name the computers during enrollment or do a pre-inventory load with computer names. Even if the prestage enrollment had a section for naming like the iPads do.
Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

Billski
New Contributor II

Hi Gabe,

Here is an approximation of the script we use.

#!/usr/bin/env python
# Python code to illustrate Sending mail with attachments
# from your email account  

# libraries to be imported 
import smtplib 
from email.mime.multipart import MIMEMultipart 
from email.mime.text import MIMEText 
from email.mime.base import MIMEBase 
from email import encoders 
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 + "
");
import sys  
fromaddr = "noreply@YOURMAILSERVER.COM"
toaddr = "@YOURMAILSERVER.COM"
#The password can be passed as a parameter value in your JSS policy (parameter 4 in this case)
passwrd = sys.argv[4] 

# instance of MIMEMultipart 
msg = MIMEMultipart() 

# storing the senders email address   
msg['From'] = fromaddr 

# storing the receivers email address  
msg['To'] = toaddr 

# storing the subject  
msg['Subject'] = "Your copy of the EULA"

# string to store the body of the mail 
body = "This is a copy of the EULA/Digital Device Agreement. Please do not reply to this email"

# attach the body with the msg instance 
msg.attach(MIMEText(body, 'plain')) 

# open the file to be sent  
filename = "NAMEOFFILE.txt"
attachment = open("/PATH/TO/FILE.txt", "rb") 

# instance of MIMEBase and named as p 
p = MIMEBase('application', 'octet-stream') 

# To change the payload into encoded form 
p.set_payload((attachment).read()) 

# encode into base64 
encoders.encode_base64(p) 

p.add_header('Content-Disposition', "attachment; filename= %s" % filename) 

# attach the instance 'p' to instance 'msg' 
msg.attach(p) 

# creates SMTP session 
s = smtplib.SMTP('ENTER.MAILSERVER.HERE', PORTHERE) 

# start TLS for security 
s.starttls() 

# Authentication 
s.login(fromaddr, passwrd) 

# Converts the Multipart msg into a string 
text = msg.as_string() 

# sending the mail 
s.sendmail(fromaddr, username + toaddr, text)

# terminating the session 
s.quit()

Sorry it took me a few days to respond. I'm not on Jamf nation that often.

Hope this helps!

Billski
New Contributor II

We also used to convert our "signed" .txt to pdf and add a few graphics here and there but we gave up on that after a few updates caused ours script to break and we decided a plain text file was good enough. Im sure you could make finished attachment prettier if you wanted to though.

GabeShack
Valued Contributor III

@Billski Thanks for this!
So far in my testing just running the @mm2270 script is working great with a few modifications. I'm having this script run after a few scripts I have happening during the users 1st login (opening various apps and pre-populating their user name/email addresses). I also added the marketing model name, and serial number to this as well. Since I only need this to run once per users computer, I have it run during that initial login, then keep the file there since the EA runs a cat of the text file at the next inventory update and then attaches it to the record. (If it doesn't find the file, it leaves the field blank). The EA then adds it to the JSS record in the Users and Location tab, which seems like a good enough place to look up that they signed off on this.

After trialing this out a few times, I think it will be perfect for newly imaged staff devices. I may push the policy to run the script out to staff who already have their computer too just to get everyone in compliance.

Thanks all for your help. Attached is my modified version if anyone else wants to use it.

#!/bin/bash

## Put full path to coocoaDialog here, wherever you deploy it to systems. Note the path all the way to the executable inside "MacOS"
CDPATH="/Users/Shared/cocoaDialogNew.app/Contents/MacOS/cocoaDialog"

## Capture the logged in user short name
loggedInUser=$( ls -l /dev/console | awk '{print $3}' )

## Get the full user name from dscl, if applicable for your environment (may need adjustment; test this separately)
fullName=$( dscl . read /Users/$loggedInUser RealName | awk -F, '{getline; print $2$1}' | sed 's/^ *//' )

## Get the computer name
compName=$( scutil --get ComputerName )

## Get the computer Serial Number
serialNumber=$( ioreg -c IOPlatformExpertDevice -d 2 | awk -F" '/IOPlatformSerialNumber/{print $(NF-1)}' )

## Get the computer model
model=$(curl -s https://support-sp.apple.com/sp/product?cc=$(
  system_profiler SPHardwareDataType 
    | awk '/Serial/ {print $4}' 
    | cut -c 9-
) | sed 's|.*<configCode>(.*)</configCode>.*|1|')

## Path to EULA file with data on disk
eulaFILE="/private/var/eula_agreement"

## Edit this text below. Note that you may need to adjust the --height integer in the cocoaDialog call to accommodate longer text
MsgText="Below is Your Company's Acceptable Use Policy.

Please read it carefully, then check the "I agree to these terms" checkbox below, and finally click "OK".

Your AUP Here"

## Main script starts here

## See who's logged in. If its not "root" we aren't sitting at the login screen.
if [[ "$loggedInUser" != "root" ]]; then

    echo "A user is logged in"

    ## Check to see if a eula_agreement file is already on disk, just in case it ran already

    if [[ ! -e "$eulaFILE" ]]; then

        echo "No previous eula_agreement file found on disk. Continuing..."

        # Display the dialog. Notes:
        # 1. The "--value-required" flag forces them to check the checkbox before the dialog can be dismissed.
        # 2. If you want a custom icon, use --icon-file instead of --icon below and enter the full path to the icon file (icns, png, jpg, etc)
        # 3. Adjustment of the --width and --height integers may be necessary. Occasionally CD doesn't rescale correctly based on the text.    
        # 4. Enter a title after --title if you want the dialog to have one. Use "" to use a blank title

        EULADialog=$( "$CDPATH" checkbox --title "Acceptable Use Policy" --label "$MsgText" 
        --items "I agree to these terms" --button1 "   OK   " --value-required 
        --icon-file "/Library/Desktop Pictures/PPSLogo.jpg" info --width 800 --height 950 )

        ## Now detect the response.
        if [[ $( echo "$EULADialog" | awk 'NR>1{print $0}' ) == "1" ]]; then

            echo "The dialog exited with the Agree button checked"
            AgreeChecked="User Clicked I Agree"

## Export the settings to a file on disk that can be picked up by recon later

echo -e "EULA agreement status:

Username:   $loggedInUser
Full Name:  $fullName
Model:  $model
Computer Name:  $compName
Computer Serial:  $serialNumber
User Agreed?:   $AgreeChecked
Agreement Date: $(date +"%b %d, %Y, %T")" > "$eulaFILE"

            ## Run a recon to suck up the EULA file. You will need an Extension Attribute designed to capture the contents of this file.
#            echo "Gathering new inventory"
#            jamf recon

            ## If the recon was successful
#            if [[ "$?" == "0" ]]; then

                ## Now, clean up
                ## Unload the LaucnhDaemon that triggers the script
#                /bin/launchctl unload /Library/LaunchDaemons/com.nameoflaunchdamon.plist
                ## Delete the LaunchDaemon
#                /bin/rm -f "/Library/LaunchDaemon/com.nameoflaunchdaemon.plist"
                ## Delete the eula file
#                /bin/rm "$eulaFILE"
                ## Delete the script last
#                /bin/rm -f "$0"

            else

#                echo "Recon failed. Let's not delete anything until we can capture the file. Exit until next run..."
                exit 0

            fi

        else

            echo "Somehow the 'I agree' box wasn't checked. Exit until next run..."
            exit 0

        fi

#    else

#        echo "An existing eula_agreement file was found. Run recon (just in case) and then delete the file..."
#        jamf recon
#        /bin/rm "$eulaFILE"
#        exit 0

#    fi

else

    ## If the logged in user is root, the Mac is still sitting at the login window. Exit and wait until the next run
    echo "There is no logged in user. Exit until next run..."
    exit 0

fi

Also here is the Extension Attribute to gather the text file into the record:

#!/bin/sh
Result=$(cat /private/var/eula_agreement)
echo "<result>$Result</result>"

Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

mm2270
Legendary Contributor III

@gshackney Just a word of caution on continuing to use cocoaDialog in your workflows. The product hasn't been updated in ages, and likely doesn't work on Big Sur and forward. I haven't actually tried it on Big Sur myself because I stopped using it a few years ago when I realized that the odds of it ever being updated again were slim to none. The developer abandoned it (though he did have a few fits and starts at trying to revive it), and no-one has come along to pick up the reins. It's too bad really. It was a great dialog creation tool and had a ton of customizable options. There really isn't anything good out there to replace it with.

But I just thought I'd mention to be careful about planning anything long term around it, since it may just not work on future OSes, if that isn't already the case.

GabeShack
Valued Contributor III

Got it, thanks @mm2270 . I looked at some of the alternatives, but none really did the same thing as well. I saw the main developer had jumped into another posting to say he just wanted people to help, and then created a website for it, but now the website no longer functions and he doesn't seem to respond.

Since the "beta" "new" "non-32bit" version still runs as long as i flag it as ok in XProtect, I'll use it for now. Guess I'll do some trials on Big Sur machines next though just to be safe. Thanks again!
Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

@mm2270 I just confirmed the same results on Big Sur 11.0.1 and can say the script is working fine with CocoaDialog. Testing again on 11.3 to be really sure lol, but at least this will work even after the next upgrade cycle for our district.
Gabe Shackney
Princeton Public Schools

Gabe Shackney
Princeton Public Schools

GabeShack
Valued Contributor III

I can confirm this is working on 11.4 again as long as you flag the XProtect feature on cocoadialogue.

Thanks all!

Gabe Shackney
Princeton Public Schools