Block iMessage during school hours

lpadmin
Contributor

At my school we are on a 1:1 program with macbook airs. We are having and issue with students using iMessage during class. I know there is a way to block and kill applications in Casper, the issue with that is I can not set a time limit on it. So I am wondering if there is a way to disable applications during a set time period?

7 REPLIES 7

mm2270
Legendary Contributor III

Hi.

A while ago, as a pure experiment, I had put together a process for Macs that would enable and disable Restricted Software from Casper based on timeframes. The only issue is, the only way I was able to do it effectively was to turn it off completely, or turn it on completely, meaning, I can't selectively enable/disable individual applications that are restricted. Its all or nothing.

I don't know if that suits you or not. In our environment, we need to block certain select applications 100% of the time, so I can't use what I developed for ourselves. If you're interested, I can outline what I did to get this to work.

lpadmin
Contributor

@mm2270, currently I do not have any apps blocked so I am interested in what you did.

boberito
Valued Contributor

In for responses. I'm also curious.

mm2270
Legendary Contributor III

Hey all,

So, the process I came up with was a combination of a LaunchDaemon and a local script.
The LaunchDaemon would trigger every 10 minutes, or 600 seconds and run the script. Here's the LaunchDaemon-

<?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.corp.rs</string>
    <key>Program</key>
    <string>/private/var/scripts/rs.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>600</integer>
</dict>
</plist>

You can set the Label to anything you want. I just used a simple generic name so it wasn't very obvious what it did.

In the script, the basic principal is to check the time when it gets run by the LaunchDaemon, and if it falls between 9 AM and 4 PM (work/school time), run one function in the script, and if it falls outside of that window (home time), run a separate function.
One note, we have an externally facing JSS with our cluster, so clients can and do check in from outside. As a result, in the script I needed to take some extra measures to be sure the existing JAMF processes would not overwrite my changes. Here is the script:

#!/bin/bash

create_XML ()
{

echo "<?xml version="1.0" encoding="UTF-8"?><blacklistitems></blacklistitems>" > "$RS_XML_FILE"

if [ "$?" == "0" ]; then
    ## If creating the stub xml was successful, set immutable flag and unload/reload the jamf LaunchDaemon
    sleep 0.5
    ## Make the file system immutable
    chflags schg "$RS_XML_FILE"
    sleep 0.5
    ## Unload and reload the jamf.daemon LaunchDaemon to load the new settings
    /bin/launchctl unload /Library/LaunchDaemons/com.jamfsoftware.jamf.daemon.plist
    sleep 1
    /bin/launchctl load /Library/LaunchDaemons/com.jamfsoftware.jamf.daemon.plist
    if [[ $(cat "$RS_XML_FILE") == "<?xml version="1.0" encoding="UTF-8"?><blacklistitems></blacklistitems>" ]] && [[ $(ls -lO "$RS_XML_FILE" | tr ' ' '
' | grep "schg") == "schg" ]]; then
        echo "XML file successfully set"
    else
        exit 0
    fi
else
    ## Creating the new xml file failed. Exit
    exit 1
fi

}

## Function to recreate a base .blacklist.xml file
disable_RS ()
{

## Define the blacklist xml file name/path
RS_XML_FILE="/Library/Application Support/JAMF/.blacklist.xml"

## Check for the xml file and get its properties
if [ -e "$RS_XML_FILE" ]; then
    XMLContent=$(cat "$RS_XML_FILE" | xpath /blacklistitems[1])
    XMLLock=$(ls -lO "$RS_XML_FILE" | tr ' ' '
' | grep "schg")
    if [[ "$XMLContent" == "<blacklistitems />" ]] && [[ "$XMLLock" == "schg" ]]; then
        echo "XML is already empty and locked"
        exit 0
    else
        ## File wasn't set correctly, so we fix that
        create_XML
    fi
else
    echo "XML file not present. Nothing needed at this time."
    create_XML
fi

}

enable_RS ()
{

## Define the blacklist xml file name/path
RS_XML_FILE="/Library/Application Support/JAMF/.blacklist.xml"

if [ -e "$RS_XML_FILE" ]; then
    if [[ $(ls -lO "$RS_XML_FILE" | tr ' ' '
' | grep "schg") == "schg" ]]; then
        ## The xml file is locked. Unlock it.
        chflags noschg "$RS_XML_FILE"
        ## If unlocking was successful, run jamf manage to update it with correct data
        if [ "$?" == "0" ]; then
            jamf manage
        else
            ## Try the function again
            enable_RS
        fi
    else
        ## System immutable flag isn't set. Run jamf manage
        jamf manage
    fi
else
    ## The xml file isn't there. Run jamf manage to have it created
    jamf manage
fi

}

## Core script. Check time, enable or disable based on scheduled timeframe

## Get the hour and minute as one string in 24 hour time
dateHour=$( date +"%H%m" )
echo "dateHour is: $dateHour"
dayOfWeek=$( date +"%a" )
echo "day of week is: $dayOfWeek"

## If the time (hour+minutes) is equal to or higher than 1600 (4:00 PM) OR lower than 900 (9:00 AM),
## then we're in the 'disable' time range

if [[ "$dayOfWeek" == "Sat" || "$dayOfWeek" == "Sun" ]]; then
    echo "We're in the weekend"
    disable_RS
else
    if [[ "$dateHour" -ge "1600" ]] || [[ "$dateHour" -le "900" ]]; then
        echo "We are between 4:00 PM and 9:00 AM on a weekday"
        disable_RS
    else
        echo "We are between 9:01 AM and 3:59 PM on a weekday"
        enable_RS
    fi
fi

What the functions do is, if outside the "restricted" time frame, remove the existing blacklist.xml file that Restricted Software uses to know what to block, then recreate a blank version (still needs to be a valid xml file) then, and this part is key if your Macs can hit your JSS from anywhere, make the xml file immutable, so even root can't make changes to it without it first being unlocked. This prevented the recurring jamf LaunchDaemon and processes from seeing that the Restricted Software xml didn't match up and pull down a new one.
Later, once the Mac is within the timeframe where it should restrict software again, like the next morning, the script unlocks and deletes the "blank" xml file, then runs a jamf manage command to pull down a new proper xml.

It also checks to see if we're on a weekend day (Sat or Sun) and will run the disable process automatically without worrying about the timeframe its in. If the xml file is missing during a "disable" timeframe, it just exits, since no xml would mean no restrictions. If it ever falls into a M-F and between certain hours, it works on enforcing the restrictions. This does require connection back to your JSS to enforce it, and of course the Mac to be properly managed.

Let me know if I can answer any other questions on this.

BTW, I had tested this by having the LaunchDaemon and script on my Mac and I checked it almost every day for a couple of weeks and it always worked as expected. Basically, after 4PM I was able to launch whatever applications I needed to and prior to that, could not.

You can adjust the time frame by just changing the values in the script line where it says:

if [[ "$dateHour" -ge 1600 ]] || [[ "$dateHour" -le 900 ]]; then

That's in 24 hour time, so basically, between 4PM and 9AM. Just raise or lower those values as needed.

jgwatson
Contributor

Why don't you just block iMessage on the schools firewall? Then have a second WiFi network turn on after school hours, or as the students will be at home, don't worry about it.

lpadmin
Contributor

@mm2270, how do I set this up on my jss?

mm2270
Legendary Contributor III

@lpadmin - the only involvement the JSS has with this would be deploying the LaunchDaemon and script to your Macs after you create them and package them up. Once done, this becomes a local process, not something managed by the JSS. That does mean you would have a local only process that, if you need to remove it or change it later, isn't as simple as just checking or unchecking a box in the JSS.

If you're OK with the potential pitfalls of the approach, I suggest getting a copy of either LaunchControl or Lingon to create the LaunchDaemon. These applications make sure the plist, permissions and ownership are set exactly as needed to work. You can do it manually, but launchd jobs are finicky and won't launch if they see anything unexpected in them.
Also note that it must be a LaunchDaemon, not a LaunchAgent, since the script has to run with root privileges. If using LaunchControl, the terminology used there is "Global Daemons"

For the script you can copy/paste from the one above into a good text editor like TextWrangler (free on the App Store) and save as a file called "rs.sh" and save into /private/var/scripts ("scripts" is directory you need to make). You can name it something different and save elsewhere if you want, but would need to make sure the path and name in the LaunchDaemon match.

Install and test them on your Mac or a test Mac. Once its working as you like, use Composer to package these items up by dragging them in from their installed locations. Test deploy it from your JSS to some Macs and see what happens.
Keep in mind that LaunchDaemons don't activate by default when installed, unless you script it to load them, or a reboot occurs. So you can decide to pair this with a mandatory reboot, or look at using launchctl to load the LaunchDaemon.
See my script for an example of loading a launched job.

Let me know if you need more help.