Mac computer lab headaches! A script to handle keychain errors, docks, and users logged in in the background

I’m primarily a university-level ESL instructor. However, one of my responsibilities is to manage our English Language Institute’s computer lab, which has 20 iMacs. Here are some of the issues I’ve struggled with:

  • Keychain errors. My university uses Active Directory for usernames and passwords, and Macs don’t play nicely with Active Directory. Every time that students and faculty are forced to change their passwords through the university’s web interface, it breaks their keychains on all campus Macs, since the login password is no longer the same as the keychain password. Dealing with keychain errors is annoying enough under one-device-per-person circumstances, but when people use multiple computers over the course of multiple semesters and change their password multiple times, the problems snowball out of control.
  • Messing up the dock. It’s pretty straightforward to set up a default dock for new users. However, most of our students lack familiarity or comfort with Macs, so if a student accidentally drags an important icon (like, say, Microsoft Word) out of the dock, they may have difficulty finding the application again. Under these circumstances, it’s desirable to “reset” the dock to a known good state every time a user logs out so that any mistakes they made will be wiped away.
  • Users not logging out. This is a big one. If a user fails to log out properly and ends up with their whole session still stored in memory in the background, system performance plummets for anyone else who logs into that computer. This is a huge problem in a lab setting because it’s difficult to train users to always properly log out, and each computer is logged into so many times every day that it only takes a couple days for most computers to have at least one user still accidentally logged in in the background.

One solution to these kinds of issues is to have a very tightly controlled computer lab where no user data is stored and where the computers constantly restart and reset themselves to known good states. But I’m not comfortable doing that; I want students to be able to log back into a computer to retrieve a file if they accidentally saved it to the lab computer instead of their personal flash drive, for example.

So instead, I wrote a logoff script to do some basic maintenance to help me solve these issues. Macs don’t provide an easy built-in way to run logoff scripts, so I use Offset to run the script for me.

My script does the following:

  1. Delete the user’s keychain every time they log out. This prevents keychain errors and improves security, since it ensures we aren’t storing people’s passwords on our public computers.
  2. Replaces the user’s dock with a known good configuration. That way, if the user accidentally messed up the dock, it will be back to normal the next time they log in.
  3. Kicks off anyone who’s logged into the computer in the background. This dramatically improves system performance.
  4. Restarts the computer if it’s been on for more than a day. This is a necessary step to fully purge keychain files.

Here is the script I created. I am not a bash expert or a MacOS expert, and I make no warranty for the functionality or safety of this script; I’m presenting it only for example purposes to help others in similar positions. If you want to adapt this script, you will likely need to make changes.

#!/bin/bash

echo "$(date) - Script execution beginning" >> /Library/Logs/lab_logout_debug.log

# Step 0: Decide whether we need to run the script.
#         If we're at the login window, and if the script has not run
#         in the last 60 seconds, then we want to run it now.
#         Note: Checking when the script last ran prevents the script from 
#         killing the login window over and over and over again in a loop!
#         I chose 600 seconds because it would be unusual for someone to be
#         logged in for less than 1 minute.

echo "$(date) - initializing shouldrun to false" >> /Library/Logs/lab_logout_debug.log
shouldrun=false

echo "$(date) - trying to find the last time run log file" >> /Library/Logs/lab_logout_debug.log

# Can we find the log file that stores the last time the script was run?
if [ -f /Library/Logs/lab_logout_last_time.log ]
then
    # We found the file!
    echo "$(date) - found last time run log file" >> /Library/Logs/lab_logout_debug.log
    
    # Store the current Unix time in seconds
    currenttime=$(date +%s)

    # Read the Unix time in seconds that the script last ran
    lasttime=$(cat /Library/Logs/lab_logout_last_time.log)

    # Calculate the difference between the times: How long ago did the script last run?
    delta=$(expr $currenttime - $lasttime)

    echo "$(date) - Current time: " $currenttime >> /Library/Logs/lab_logout_debug.log
    echo "$(date) - Last time: " $lasttime >> /Library/Logs/lab_logout_debug.log
    echo "$(date) - Delta: " $delta >> /Library/Logs/lab_logout_debug.log

    # Did the script last run MORE than 60 seconds ago?
    if [ "$delta" -gt 60 ]
    then
        # Yes? We should run the script.
        shouldrun=true
        echo "$(date) - set shouldrun to true (delta large enough)" >> /Library/Logs/lab_logout_debug.log
    else
        # No? We should not run the script.
        echo "$(date) - keep shouldrun at false (delta too small)" >> /Library/Logs/lab_logout_debug.log
    fi
else
    # We didn't find the log file that stores the last time the script was run, so let's assume we need to run the script.
    echo "$(date) - didn't find file" >> /Library/Logs/lab_logout_debug.log
    shouldrun=true
    echo "$(date) - set shouldrun to true (file not found)" >> /Library/Logs/lab_logout_debug.log
fi

# Should we run the script?
if [ "$shouldrun" = "true" ]
then
    # Yes, we should run the script!
    echo "$(date) - shouldrun evaluated as true - executing remainder of script" >> /Library/Logs/lab_logout_debug.log
    echo "$(date) - Executing lab logout script." >> /Library/Logs/lab_logout.log

    ### Step 1: Delete the last user's keychain
    # Credit to https://github.com/aysiu/Mac-Scripts-and-Profiles/blob/master/RemoveLastUserKeychains

    echo "$(date) - Entering step 1" >> /Library/Logs/lab_logout_debug.log

    # Get the last user's username
    lastUserName=$(defaults read /Library/Preferences/com.apple.loginwindow lastUserName)

    # Remove the keychains for that user
    sudo rm -rf /Users/"$lastUserName"/Library/Keychains/*
    sudo rm -rf /Users/"$lastUserName"/Library/Keychains/.f*

    # Add to log file
    sudo echo "$(date) - Keychain deleted for $lastUserName" >> /Library/Logs/lab_logout.log

    ### Step 2: Copy the dock for the user

    echo "$(date) - Entering step 2" >> /Library/Logs/lab_logout_debug.log

    cp /Library/lab/com.apple.dock.plist /Users/$lastUserName/Library/Preferences/
    echo "$(date) - Dock copied for this user:" $lastUserName >> /Library/Logs/lab_logout.log

    ### Step 3: Record the current time as the last time the script ran

    echo "$(date) - Entering step 3" >> /Library/Logs/lab_logout_debug.log

    # Record the current time to the lab_logout_last_time file, overwriting any previous file content
    echo $(date +%s) > /Library/Logs/lab_logout_last_time.log

    echo "$(date) - Current time recorded" >> /Library/Logs/lab_logout_debug.log

    ### Step 4: Either restart (if uptime is at least 1 day) or kill loginwindow (to log out any background users)
    echo "$(date) - Entering step 4" >> /Library/Logs/lab_logout_debug.log
    echo "$(date) - Current uptime: $(uptime)" >> /Library/Logs/lab_logout_debug.log

    # Has the computer been on for at least one full day? 
    # (i.e. does the word "day" or "days" appear in the output of the "uptime" command?)
    if [[ $(uptime) =~ .*day.* ]] 
    then 
        # Uptime is at least one day, so let's restart. This will fully clear keychains and (obviously) log out all users.

        echo "$(date) - Uptime greater than a day; attempting a restart" >> /Library/Logs/lab_logout.log
        sudo shutdown -r now
    else 
        # Uptime is less than one day, so let's just kill the loginwindow process to make sure no one's
        # logged in in the background.

        echo "$(date) - Uptime less than a day; killing loginwindow." >> /Library/Logs/lab_logout.log

        # Kill loginwindow to log out any users who are logged in in the background
        sudo pkill loginwindow
    fi
    
else
    # No, we shouldn't run the script!
    echo "$(date) - shouldrun DID NOT evaluate as true" >> /Library/Logs/lab_logout_debug.log
fi
done

Basic installation instructions:

  1. Install Offset.
  2. Paste my script into a new file with a .sh extension.
  3. Make any necessary changes to the script. Note that it won’t run as-is; at the very least, you need to put a dock.plist file in the /Library/lab/ directory for step 2 of the script, or else remove that part of the script.
  4. Move the script file to /usr/local/offset/logout-every so that Offset will run it for you.
  5. Make the script file executable. I run this command in Terminal, and it seems to work, but I’m not an expert, so ymmv: sudo chmod 755 /usr/local/offset/logout-every/lab_logout.sh ; sudo chown root:wheel /usr/local/offset/logout-every/lab_logout.sh

That should do it!

ELI Computer Lab Class: Week 10 – Career Resources

Some of you will go on to have careers (temporary or permanent) in an English-speaking country. You may find some of these resources helpful when looking for and applying for positions!

  • Résumé / CV: Everyone needs a short (1-2 page) résumé. If your focus is academic, you should have a full CV (curriculum vitae) as well. There are many websites which can help you create an attractive résumé, and many have a “free” option. However, you usually need to pay if you want a good-quality résumé. Here are some recent reviews of ten résumé building websites.
  • Cover letters: Most job listings require you to write a cover letter. The main purpose of a cover letter is to demonstrate that you are an excellent fit for the job you are applying for. Beyond that, expectations and traditions for cover letters are different in every field, so it is good to ask people in your field for advice. Purdue OWL has an excellent resource for writing your cover letter.
  • Business cards: Business cards are small cards that have your contact information on them. They are a very useful thing to bring to business meetings, conferences, and job fairs. There are many websites that can help you design and print business cards. Here is a recent listing of six business card websites.
  • LinkedIn profile: LinkedIn is a social network focused on jobs and careers. It is a good idea to create a LinkedIn profile and to include the link on your résumé. LinkedIn is a good way to network and to make friends in your field.
  • Job listing websites: There are many ways to find good jobs. One of the best and most effective ways is through networking (“word-of-mouth”), when friends tell each other about open jobs. However, there are also websites that help you search for job listings in your field. Two popular choices are Indeed and SimplyHired.
  • Company reputations: When you’re considering a company to work for, it’s good to know what current and former employees think of that company. GlassDoor is a popular website that lets people review their companies and express whether they are good or bad places to work.
  • Salary ranges: Salary negotiation is often one of the most difficult and confusing parts of getting a job. GlassDoor is one place to find out what people in your field are usually paid. Many other websites also exist for this purpose, including PayScale.

ELI Computer Lab Class: Week 9 – Organization and Motivation

Hello! The end of the semester is getting very close. And you know what that means: we have a lot of major projects, papers, and exams to deal with! This week, I would like to share a couple of tools that might help you organize your work and motivate yourself to be more productive: Trello and Habitica.

Trello

Trello (https://trello.com/) is a website that helps you create and organize to-do lists. It is especially designed for teams working together on a project, but people use it for personal to-do lists as well.

There are many ways to organize and prioritize your tasks on Trello. Here are two simple examples:

Using Trello to keep track of what you're doing now, what you need to do later, and what you have already finished
Using Trello to keep track of what you’re doing now, what you need to do later, and what you have already finished
Using Trello to plan when you will do each task.
Using Trello to plan when you will do each task.

 

Habitica

Habitica (https://habitica.com/) is a website that helps you turn your goals into games. As you study and complete assignments in real life, you earn rewards in the game. This is designed to help you keep your motivation high.

I hope one or both of these resources helps you to achieve your goals for the end of the semester. Good luck!

ELI Computer Lab Class: Week 8 – Vocabulary Profilers

Hello! This week, my suggested resource is a tool called a vocabulary profiler.

In your ELI classes, your textbooks and your teachers help you to preview vocabulary before you read a new text. But outside of the classroom, how can you preview vocabulary in the real world!?

A vocabulary profiler can analyze a text and show you which words you probably need to focus on and preview. The profiler finds all of the interesting or unusual vocabulary the text has. You can use this information to help you prepare to read (or listen to) a new text!

Click the link below to begin:

http://www.lextutor.ca/vp/comp/

Here is a profile for a TED talk titled “How we can make the world a better place by 2030”:

A of How we can make the world a better place by 2030
A vocabulary profile of How we can make the world a better place by 2030

On the left is the original text which I copied and pasted into the website. On the right is a colored text showing how common each word is. The most common and simple words are blue and green, while the least common words are colors like orange and people.

Here’s the important part:

In the middle is a list of uncommon English words that are used often in this text. For example, this text uses the word “capita” four times, “economy” 14 times, “forecast” four times, and “poverty” six times. If you don’t understand what those words mean, you will probably have difficulty understanding the speech! So you should review that list carefully and preview the vocabulary before reading or listening to the speech.

Give it a try: paste text from a newspaper article, magazine article, or TED.com into the vocabulary profiler and see what you discover!