1. Overview

Sometimes, we might want to automate the user creation process without having to interact with the command line.

In this tutorial, we’ll write a robust shell script for automating the user creation process. We’ll make use of the built-in tools that ship with most Linux distributions, building up our script as we progress through the sections of the tutorial.

We should note that these commands must be run as root.

2. Setting Up the Automation Script

We’ll start up by performing validation checks such as checking whether the user already exists and assigning a default password if none was provided. Afterward, we’ll go through a few variations on the actual user creation and password assignment.

Then, we’ll execute the script from the command line and provide it with the –username and –password arguments.

In case of validation errors, we’ll be presented with the script usage message that contains the instructions. Once the script executes successfully, we’ll print out the username and the password.

Before we proceed, let’s have a glimpse of the final script, then go through each section expounding more on what’s happening:

#!/bin/sh

usage() {
  printf "create-user [-u|--username] <username>\n"
  printf " OPTIONS\n"
  printf "  -u --username\tusername of the new account (required)\n"
  printf "  -p --password\tpassword for the new account (optional)\n"
  printf "  -h --help\tprint this help\n"
  exit 1
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    -u|--username) username="$2" shift ;;
    -p|--password) password="$2" shift ;;
        -h|--help) usage ;;
                *) usage ;;
  esac
  shift
done

[ -z "$username" ] && usage
[ -z "$password" ] && password=$(uuidgen | cut -d'-' -f1)

useradd -m -p $(echo "$password" | openssl passwd -1 -stdin) $username > /dev/null 2>&1

#------------#
# VARIATIONS #
#------------#
# useradd -m "$username"
# echo -n "$password\n$password\n" | passwd $username"
# echo "${username}:${password}" | chpasswd

if [ "$?" -eq 0 ]; then
  echo "Username: $username"
  echo "Password: $password"
else
  echo "Failed to set up user account"
  userdel -f "$username"
fi

In this script, we’re starting with writing the usage function in case of any errors:

#!/bin/sh

usage() {
  printf "create-user [-u|--username] <username>\n"
  printf " OPTIONS\n"
  printf "  -u --username\tusername of the new account (required)\n"
  printf "  -p --password\tpassword for the new account (optional)\n"
  printf "  -h --help\tprint this help\n"
  exit 1
}

It’s a UNIX and Linux convention to have the usage function included in our scripts.

Next, we’re processing the command options by iterating through the arguments using a while loop and assigning the values to variables.

Afterward, we’re carrying out sanity checks and assigning a default password if it isn’t provided as an argument:

while [ "$" -gt 0 ]; do
  case "$1" in
    -u|--username) username="$2" shift ;;
    -p|--password) password="$2" shift ;;
        -h|--help) usage ;;
                *) usage ;;
  esac
  shift
done

[ -z "$username" ] && usage
[ -z "$password" ] && password=$(uuidgen | cut -d'-' -f1)

If no username was provided, we print out the usage for the script and exit the program with exit code 1. In the case of a missing password, we’ve used the uuidgen command that generates a UUID. In our case, we only need the first eight characters of the generated UUID for the default password.

2.1. Check Whether User Exists

Sometimes, we might have an existing user with the same username as the username argument. Therefore, we’d need to check for the existing user in the user database beforehand. We can use the userdbctl command. We use the userdbctl command to query the user database on a Linux machine.

The userdbctl command returns exit code 1 for users that do not exist in the user databaseOtherwise, it will return 0:

$ userdbctl user "$username" > /dev/null 2>&1
[ "$?" -eq 0 ] && echo "$username already exists" && exit 2

In the above snippet, we run the userdbctl command and check for the exit code it returns. The $? operator contains the exit code of the latest command we execute in the script. In this case, it will contain either a 0 or a 1.

Of course, we can leave this safety check, as the useradd command will fail if the user already exists. However, we need some kind of simple feedback that goes well with our script because useradd will return exit code 9 for a username that already exists.

3. Creating a User and Assigning Password

Now that the pre-checks are complete, we’ll move on to creating the actual user.

We’re using the useradd command for user creation:

useradd -m -p $(echo "$password" | openssl passwd -1 -stdin) $username > /dev/null 2>&1

Here, the -m flag creates a home directory for the user. We’re then using OpenSSL to hash the password using SHA-512 encryption. We’re passing an encrypted password because the -p option expects an encrypted password returned by crypt. The -1 option above returns an MD5 password hash.

Alternatively, we can also hide the password in output logs by modifying the command above:

$ useradd -m -p $(read -sp Password: pw ; echo $pw | openssl passwd -1 -stdin) $username > /dev/null 2>&1

The command above will give us a prompt to enter a password that isn’t outputted in logs. This offers us more security over the whole process.

Let’s explore a few other variations for assigning the password.

3.1. Using useraddecho, and passwd Commands

The passwd command creates or changes the password for an existing user account. It takes a username as an argument and presents an interactive prompt for password modification.

Let’s change the password for the newuser that we just created:

$ passwd newuser
Changing password for newuser.
Current password:
New password:
Retype new password:
passwd: password updated successfully

As we can see, the passwd command presents us with an interactive prompt. For that reason, we’ll make use of the echo command alongside passwd to skip the interactive prompt.

The echo command is a utility that takes input from the standard input and prints it to the standard output. We can also pipe echo with other commands to bypass prompts and confirmation messages. Therefore, we can easily automate tasks that involve prompts either in a shell script or in the Linux terminal.

Let’s see it in action:

$ echo -en "strongpassword\nnewpass\nnewpass\n" | passwd newuser
Changing password for newuser.
Current password:
New password:
Retype new password:
passwd: password updated successfully

Here’s what happened:

  • We enabled the escape sequence characters support for the echo command through the -e flag.
  • The -n flag disables printing the trailing newline.
  • We echo the current password followed by the new and confirmed password.
  • Each password is separated by the “\n” character, so they are treated as three separate standard inputs.
  • The output from the echo command is piped to the passwd command, which we used to change the password for newuser.

Now that we have some idea of how to bypass prompts using echo, we can implement this in our script instead of providing the password to the useradd command:

$ useradd -m "$username" > /dev/null 2>&1
echo -n "$password\n$password\n" | passwd "$username" /dev/null 2>&1

3.2. Using useraddecho, and chpasswd Commands

Alternatively, we can use the chpasswd command to change the password for new users. It performs the same function as passwd.

Let’s see it in action:

$ chpasswd
newuser:secretpasscode

Like passwdchpasswd will present us with an interactive multi-line prompt. We write the username followed by a colon (:) and the new password. Afterward, we can press CTRL+D to apply the changes. Like passwd, we can also use the echo command to automate this process:

$ echo "newuser:code7654" | chpasswd

Now that we’re familiar with chpasswd, we can use it instead of passwd in our script:

$ useradd -m "$username"
echo "${username}:${password}" | chpasswd

4. Finishing Touches

Finally, we’re writing the feedback code that lets a user know that the user is created successfully:

if [ "$?" -eq 0 ]; then
  echo "Username: $username"
  echo "Password: $password"
else
  echo "Failed to set up user account"
  userdel -f "$username"
fi

We’re checking for the exit code of the latest command that’s executed in the script, which might be useraddpasswd, or chpasswd, depending on the variation used.

Let’s break down the statement above:

  • We’re checking for the exit code of the previously executed command and expect it to be equal to 0.
  • If it’s 0, which usually indicates success, we print out the username and password.
  • In case of failure, we print out the failure message and remove the user from the user database using the userdel command if it’s been created.
  • The -f flag forces userdel to remove the user – even if the user is still logged in – along with their home directory and mail spool.

We’re now ready to test out the script:

$ sudo ./create-user -u "johndoe" -p "ys2b7444"
Username: johndoe
Password: ys2b7444
$ sudo ./create-user -u "doejohn"
Username: doejohn
Password: 89c871de
$ sudo ./create-user -u johndoe
johndoe already exists
$ sudo ./create-user
create-user [-u|--username] <username>
OPTIONS
 -u --username  username of the new account (required)
 -p --password  password for the new account (optional)
 -h --help      print this help