Make a .sh that sets new username, hostname and password

I am distributing a VM to my students for a beginners programming course. For speed, instead of getting them to install Ubuntu from scratch, I'm planning to give them a fully set up image that they can just run.

In order to get it set up I've given it a sacrificial hostname, username and password. What's the cleanest way to change this for the students when they get up and running?

I've got as far as this gist, which has some unreliable progress with the hostname, but the username is resisting me changing it.

I'd like it to be as painless a process as possible as this is supposed to happen in their first lab.

It's entirely possible that there is a completely different approach that I ought to take. I'm open to all suggestions.

#!/bin/bash
clear
toilet  "     CODE1161     "  --metal --font future
echo    ""
toilet  "Let's get started!"  --metal --font future
echo    ""
echo    "We need to make this computer be YOURS"
echo    "We need a name for you and your computer, make it short or it'll take up a lot of space."
echo    "My computer is called um and my name is ben, so I get ben@um:~$ as my command prompt."
echo    ""
read -p "Enter a name for your computer:"  compname
read -p "Enter your name: "  username
echo    ""
toilet  "$username@$compname~$"  --gay --font wideterm
echo    ""
echo    "What do you think? If you hate it, press ctrl+c and do this again"
read -p "otherwise, just press enter." sacrificial

# set the host name, in a million places, for some unknown reason.
echo "1"
sed -i "/127\.0\.1\.1\s*vc/ { c \
127.0.1.1   $compname
}" /etc/hosts
echo "2"
sudo hostname -b $compname
echo "3"
sudo hostnamectl set-hostname $compname
echo "4"
sudo groupadd $username
echo "5"
sudo usermod -d /home/$username -m -g $username -l $username ben

a screen shot of the output progress


Solution 1:

Why not just use an OEM installation for this? It's not as pretty, but it gets the job done. If you want to go down this route, see izx's excellent answer to this question: How do I pre-install Ubuntu for someone (OEM install)?

Basically, the system will (on first boot) prompt the user for a bunch of information to personalize their machine. This includes the language, location, username, hostname, password, and so on. Basically, everything that your computer will usually prompt you with for an installation.

This is exactly what OEM images are meant for, and they do a great job of it. Plus, you'll give your students a small taste of the "install Ubuntu" experience. Though, Ubuntu installs aren't exactly painful. You can probably do it in a single class, and give your students some homework to personalize and explore their VM. Plus, partitioning is painful fun!


Back to the problem at hand (and an answer to your actual question).....

Let's look at man usermod to get an explanation for what's going on:

CAVEATS
   You must make certain that the named user is not executing any
   processes when this command is being executed if the user's numerical
   user ID, the user's name, or the user's home directory is being
   changed.  usermod checks this on Linux, but only check if the user is
   logged in according to utmp on other architectures.

Basically, this just means we can't change a user's UID, their username, home directory, or anything of the sort if the user is logged in.

So, we can do some fun stuff to set this up on the system's next boot. Instead of your script doing the work, we make your script make another script to do all the heavy lifting and manipulation. An example of this:

# Make the first-run script
touch /etc/init.d/firstrun-setup.sh

# Add in user modifier
echo "usermod -d /home/$username -m -g $username -l $username ben" >> /etc/init.d/firstrun-setup.sh

# Add in group rename
echo "groupmod -n $username ben" >> /etc/init.d/firstrun-setup.sh

# Add in password expiry
echo "passwd -e $username" >> /etc/init.d/firstrun-setup.sh

# Add in file self-destruct
echo "rm /etc/init.d/firstrun-setup.sh" >> /etc/init.d/firstrun-setup.sh

# Mark the file as executable
chmod a+x /etc/init.d/firstrun-setup.sh

# Reboot the computer
reboot

Basically, by doing this, you're "queueing" events to run on the system's next boot. This will run before the userland happens, so the system will execute these commands as root. Therefore, the ben user won't be logged in, and the system won't complain.

You may still need to add additional commands to this thing to allow more personalization (like setting the actual name, etc). However, this is optional and only needs to be done if you want it to take place during the setup script.

Though, it may be a good idea to just create a new user for the students entirely, and then keep your existing sacrificial account in place. This way, if something happens, you can go in and repair/administrate their machine if at all necessary. Of course, if you're giving your students admin access to their VM, this is sort of a moot point as they might very well delete the "instructor" user because they're students.