Linux User Creation Bash Script
Tags: bash, devops, beginners
Published: 2024-07-03 16:32:47

Hey guys, been a while since my last article on Network Programming Series. While I'll very much start writing soon and continue the next article on the series, let me quickly walk you through how I did my HNG stage 1 task.

[HNG](https://hng.tech/) is a set of program designed for intermediate to advanced learners who want to rapidly move forward in their career - and end up in jobs in the best international companies. To achieve their mission of enhancing the skills of developers and make them Job ready, they arranged a 2-month transformative internship, widely known as [HNG INTERNSHIP](https://hng.tech/internship).

As part of the custom, we're to complete a task every week to move up the stages and I guess this is me about to walk you through how I did my Stage 1 task.

## Task Description

Your company has employed many new developers. As a SysOps engineer, write a bash script called create_users.sh that reads a text file containing the employee’s usernames and group names, where each line is formatted as user;groups.

The script should create users and groups as specified, set up home directories with appropriate permissions and ownership, generate random passwords for the users, and log all actions to /var/log/user_management.log. Additionally, store the generated passwords securely in /var/secure/user_passwords.txt.

## Requirements

- Each User must have a personal group with the same group name as the username, this group name will not be written in the text file.

- A user can have multiple groups, each group delimited by comma ","

- Usernames and user groups are separated by semicolon ";"- Ignore whitespace e.g.  light; sudo,dev,www-data  idimma; sudo  mayowa; dev,www-data

- For the first line, light is username and groups are sudo, dev, www-data

## My Solution

```
//create_users.sh file
#!/bin/bash //add this to the top of the file to indicate how it should be interpreted

# Check if the user list file is provided as an argument
if [ $# -ne 1 ]; then
  echo "Usage: $0 <user_list_file>"
  exit 1
fi

# Define the user list file from the argument
USER_FILE="$1"

# Check if the user list file exists
if [ ! -f "$USER_FILE" ]; then
  echo "User list file $USER_FILE not found!"
  exit 1
fi

LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"

# Ensure the log and password files exist
sudo touch $LOG_FILE
sudo chmod 666 $LOG_FILE
mkdir -p /var/secure
sudo touch $PASSWORD_FILE
sudo chmod 666 $PASSWORD_FILE

# Function to generate a random password
generate_password() {
  < /dev/urandom tr -dc 'A-Za-z0-9!@#$%^&*()_+=' | head -c 12
}

# Read the user file
while IFS=';' read -r username groups || [ -n "$username" ]; do
    if id "$username" &>/dev/null; then
        echo "User $username already exists." | tee -a $LOG_FILE
    else
    # Create the user with a home directory
    sudo useradd -m -s /bin/bash "$username"
    echo "Created user $username." | tee -a $LOG_FILE

    # Generate and set a random password
    password=$(generate_password)
    echo "$username:$password" | sudo chpasswd
    echo "$username:$password" >> $PASSWORD_FILE
    echo "Password for user $username set." | tee -a $LOG_FILE

    # Set ownership and permissions for the home directory
    sudo chown "$username:$username" /home/$username
    sudo chmod 700 /home/$username
    echo "Home directory permissions set for $username." | tee -a $LOG_FILE

    # Handle groups
    IFS=',' read -ra group_list <<< "$groups"
    for group in "${group_list[@]}"; do
      if getent group "$group" &>/dev/null; then
        echo "Group $group already exists." | sudo tee -a $LOG_FILE
      else
        sudo groupadd "$group"
        echo "Created group $group." | tee -a $LOG_FILE
      fi
      sudo usermod -aG "$group" "$username"
      echo "Added user $username to group $group." | sudo tee -a $LOG_FILE
    done
  fi
done < "$USER_FILE"
```

**Here's what each line does...**

```
#!/bin/bash
```

- This is the shebang line that tells the system to use the Bash interpreter to execute this script.

```
if [ $# -ne 1 ]; then
  echo "Usage: $0 <user_list_file>"
  exit 1
fi
```

- This section checks if exactly one argument (the user list file) is provided when the script is run. If not, it prints a usage message and exits with an error code.

```
USER_FILE="$1"
```

- This line assigns the provided argument to the USER_FILE variable, which will be used to refer to the user list file throughout the script.

```
if [ ! -f "$USER_FILE" ]; then
  echo "User list file $USER_FILE not found!"
  exit 1
fi
```

- This section checks if the specified user list file exists. If not, it prints an error message and exits.

```
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"
sudo touch $LOG_FILE
sudo chmod 777 $LOG_FILE
mkdir -p /var/secure
sudo touch $PASSWORD_FILE
sudo chmod 777 $PASSWORD_FILE
```

- These lines define the paths for the log file and the password file and then create the log and password files if they do not already exist and set their permissions to be writable by any users.

```
generate_password() {
  < /dev/urandom tr -dc 'A-Za-z0-9!@#$%^&*()_+=' | head -c 12
}
```

- This function generates a random 12-character password using characters from a specified set. It reads from /dev/urandom, which is a pseudo-random number generator.

```
while IFS=';' read -r username groups || [ -n "$username" ]; do

```
- This line starts a while loop that reads each line from the user list file. The IFS=';' sets the internal field separator to ;, so the line is split into username and groups. The || [ -n "$username" ] part ensures the last line is processed even if it doesn't end with a newline character.

```
    if id "$username" &>/dev/null; then
        echo "User $username already exists." | tee -a $LOG_FILE
    else

```

- This block checks if the user already exists using the id command. If the user exists, it logs a message to the log file and continues to the next iteration.

```
    
    sudo useradd -m -s /bin/bash "$username"
    echo "Created user $username." | tee -a $LOG_FILE
```

- If the user does not exist, this block creates the user with a home directory and sets the default shell to Bash. It then logs the action.

```

    password=$(generate_password)
    echo "$username:$password" | sudo chpasswd
    echo "$username:$password" >> $PASSWORD_FILE
    echo "Password for user $username set." | sudo tee -a $LOG_FILE
```

- This section generates a random password using the generate_password function, sets the user's password, and logs the password in the password file and the action in the log file.

```
    sudo chown "$username:$username" /home/$username
    sudo chmod 700 /home/$username
    echo "Home directory permissions set for $username." | sudo tee -a $LOG_FILE
```

- This block sets the ownership of the user's home directory to the user and sets the permissions to 700 (read, write, and execute only by the owner). It then logs the action.

```
    IFS=',' read -ra group_list <<< "$groups"
    for group in "${group_list[@]}"; do
      if getent group "$group" &>/dev/null; then
        echo "Group $group already exists." | sudo tee -a $LOG_FILE
      else
        sudo groupadd "$group"
        echo "Created group $group." | sudo tee -a $LOG_FILE
      fi
      sudo usermod -aG "$group" "$username"
      echo "Added user $username to group $group." | sudo tee -a $LOG_FILE
    done
  fi
done < "$USER_FILE"
```

- This section handles group assignments for the user. It splits the groups field into an array using , as a separator and iterates over each group. For each group, it checks if the group exists; if not, it creates the group. Then, it adds the user to the group and logs the actions.

So that's it. I want to point out though that the internship is a great opportunity to both learn and network, and interestingly, even if you couldn't finish, you can remain connected to their community and enjoy the same benefits as the finalists if you upgrade your account to premium. Check out their Premium benefits [here](https://hng.tech/premium)

I'll keep you posted on my next article.