Writing a User Creation Script in Linux Bash
Tags: webdev, beginners, tutorial
Published: 2024-07-02 07:46:12

If you've never written a bash script before, today you'll be seeing how to write one.

Bash scripts are used to automate linux processes. Knowing how to write and implement them will serve you well in your devops journey.

In this article, I'll be showing you how I wrote a bash script that automates the process of creating users, assigning groups, setting up home directories, and managing passwords on a Unix-like system. The script also logs actions and handles errors efficiently.

**Overview of the Script**

**Prerequisites**

1. You must have a functional ubuntu terminal that you can test the script(create_users.sh) from. 

2. The script must be run with root privileges to perform administrative tasks.

3. The input file must contain usernames and groups in the format: username;group1,group2.

```
#!/bin/bash

# Check if the script is run as root, if not re-execute it with sudo
if [ "$EUID" -ne 0 ]; then
    echo "This script must be run as root. Re-executing with sudo..."
    sudo bash "$0" "$@"
    exit $?
fi


# Define paths to log and password file 
LOGGER="var/log/user_management.log"
PASSWORD_FILE="var/secure/user_passwords.txt"


# Ensure directories and files exist with necessary permissions
sudo mkdir -p var/log
sudo mkdir -p var/secure
sudo chmod 700 /var/secure
sudo touch $LOGGER
sudo chmod 600 /var/secure/user_passwords.txt
sudo chown root:root /var/secure/user_passwords.txt
sudo touch $PASSWORD_FILE

# Function for generating logs
logging_function(){
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" >> $LOGGER
}

# Function for generating random passwords
password_generator(){
    tr -dc A-Za-z0-9 </dev/urandom | head -c 12
}

# Check if a user text file was provided
if [ -z "$1" ];then 
  echo "Usage: $0 <user_file>"
  exit 1
fi

# Read the file line by line and loop through
while IFS=';' read -r user groups || [ -n "$user" ]; do
  # Trimming whitespace
  user=$(echo "$user" | xargs)
  groups=$(echo "$groups" | xargs)
  
  # Skip empty lines
  [ -z "$user" ] && continue
   
  # Check if user already exists
  if id "$user" &>/dev/null;  then
    logging_function "User $user already exists."
    continue
  fi
  
  # Create user and generate password
  password=$(password_generator)
  sudo useradd -m -s /bin/bash "$user"
    if [ $? -ne 0 ]; then
        log_action "Failed to create user $user"
        continue
    fi
  echo "$user:password" | chpasswd

  logging_function "User $user created with home directory"
   
  # Create personal group and assign to user
  sudo usermod -aG "$user" "$user"

  # Assign additional groups to user
  IFS=',' read -ra group_array <<< "$groups"
  for group in "${group_array[@]}"; do
    group=$(echo $group | xargs)
    if [ -n "$group" ]; then
        if ! getent group "$group" > /dev/null 2>&1; then
            groupadd "$group"
            logging_function "Group $group created"
        fi
        usermod -aG "$group" "$user"
        logging_function "User $user added to group $group"
    fi
    done
    
    # Set home directory permissions
    sudo chmod 700 /home/$user
    sudo chown $user:$user /home/$user
    
    # Store password securely
    echo "$user, $password" >> $PASSWORD_FILE
    logging_function "password for $user stored"
done < "$1"

#Give a success response
echo "User creation complete. Check $LOGGER"

```
This is the full script. I named it create_users.sh

**Script Breakdown**
Let's dive into the script line-by-line.

**Self-Elevation Check**
```
#!/bin/bash

```
This shebang line indicates that the script should be run using the bash shell.

```
if [ "$EUID" -ne 0 ]; then
    echo "This script must be run as root. Re-executing with sudo..."
    sudo bash "$0" "$@"
    exit $?
fi
```
This block checks if the script is being run as the root user. If not, it re-executes itself with sudo to gain root privileges and exits with the same status code as the sudo command. Cool, right?

**Define Log and Password File Paths**

```
LOGGER="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"
```
These lines define the paths for the log file and the password file where actions and generated passwords will be stored.


**Ensure Directories and Files Exist**
```
sudo mkdir -p /var/log
sudo mkdir -p /var/secure
sudo chmod 700 /var/secure
```
This section ensures that the required directories exist and sets appropriate permissions. The -p option in mkdir creates the directory only if it doesn't exist.


```
sudo touch $LOGGER
sudo touch $PASSWORD_FILE
sudo chmod 600 $PASSWORD_FILE
sudo chown root:root $PASSWORD_FILE
```
These commands create the log and password files if they don't exist and set their permissions to ensure only the root user can read and write them.

**Logging Function**
```
logging_function() {
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $1" >> $LOGGER
}
```
This function logs a message to the log file with a timestamp. It appends the message ($1) to the log file.

**Password Generator**
```
password_generator() {
    tr -dc A-Za-z0-9 </dev/urandom | head -c 12
}
```
This function generates a random 12-character password using /dev/urandom for randomness.

**Check for User File**
```
if [ -z "$1" ]; then 
    echo "Usage: $0 <user_file>"
    exit 1
fi
```
This block checks if an input file was provided as an argument. If not, it displays usage information and exits.

**Read File Line by Line**
```
while IFS=';' read -r user groups || [ -n "$user" ]; do

```
This while loop reads the input file line-by-line. IFS=';' sets the internal field separator to ;, and read -r user groups reads each line into the user and groups variables. The || [ -n "$user" ] part ensures the loop processes the last line even if it doesn't end with a newline.

**Trim Whitespace**
```
user=$(echo "$user" | xargs)
groups=$(echo "$groups" | xargs)

```
These lines remove leading and trailing whitespace from the user and groups variables using xargs.

**Skip Empty Lines**
```
[ -z "$user" ] && continue

```
This condition skips empty lines by continuing to the next iteration of the loop if user is empty.


**Check if User Exists**
```
if id "$user" &>/dev/null; then
    logging_function "User $user already exists."
    continue
fi
```
This block checks if the user already exists using the id command. If the user exists, it logs the information and skips to the next iteration.

**Create User and Set Password**
```
password=$(password_generator)
sudo useradd -m -s /bin/bash "$user"
if [ $? -ne 0 ]; then
    logging_function "Failed to create user $user"
    continue
fi
echo "$user:$password" | sudo chpasswd

```
Here, a random password is generated, and the useradd command creates a new user with a home directory and sets the shell to /bin/bash. If useradd fails, it logs the failure and continues to the next iteration. The chpasswd command sets the user's password.

**Log User Creation**
```
logging_function "User $user created with home directory"

```
This line logs the successful creation of the user and their home directory.

**Create Personal Group**
```
sudo usermod -aG "$user" "$user"

```
This command adds the user to their personal group, which is named the same as the username.

**Assign Additional Groups**
```
IFS=',' read -ra group_array <<< "$groups"
for group in "${group_array[@]}"; do
    group=$(echo $group | xargs)
    if [ -n "$group" ]; then
        if ! getent group "$group" > /dev/null 2>&1; then
            sudo groupadd "$group"
            logging_function "Group $group created"
        fi
        sudo usermod -aG "$group" "$user"
        logging_function "User $user added to group $group"
    fi
done
```
This block assigns additional groups to the user. It splits the groups variable into an array using IFS=',', and then iterates over each group. If the group doesn't exist, it is created. The user is then added to each group, and the actions are logged.

**Set Home Directory Permissions**
```
sudo chmod 700 /home/$user
sudo chown $user:$user /home/$user
```
These commands set the permissions and ownership of the user's home directory to ensure it's secure and owned by the user.

**Store Password Securely**
```
echo "$user, $password" >> $PASSWORD_FILE
logging_function "Password for $user stored"
```
The user's password is stored in the password file, and the action is logged.

**End of Script**
```
done < "$1"

echo "User creation complete. Check $LOGGER"
```

The done < "$1" line marks the end of the while loop, which reads from the input file. The final echo statement informs the user that the process is complete and advises checking the log file for details.

**Conclusion**
This script provides a comprehensive solution for user management in a Unix-like system. It ensures that users are created with secure passwords, assigned to appropriate groups, and have their actions logged for auditing purposes. By understanding each line of the script, administrators can modify and extend it to fit their specific needs.

**Learn More**
For more information on automation scripts and enhancing your technical skills, consider exploring the [HNG Internship program](https://hng.tech/internship). If you are looking to hire skilled developers, visit [HNG Hire]( https://hng.tech/hire) to find top talent.