Automating User and Group Management with a Bash Script
Tags: devops, linux, cloud, automation
Published: 2024-07-03 14:17:31

> 
I recently got accepted into the famous(https://hng.tech/hire). It is a very intense hands-on 8 week program where your skills will be tested and legends are made. As a requirement for proceeding to the next stage, interns on every track are given tasks they are expected to execute, document and write an article to pass. this blog post is such.
I would recommend anyone willing to upskill and gain employable skill to enroll into the program. (https://hng.tech/premium) https://hng.tech/internship
> 
 
Hey there, fellow Sysadmin! We can all agree that managing users and groups is a bit difficult and time consuming. Trust me, I've been there. Picture this: it's 2 AM, you're knee-deep in energy drink cans, trying to add the 50th user to your system. Your eyes are crossing, and you're pretty sure you just gave someone access to critical codes by mistake. We've all been there, right? Well, chin up, because I'm about to introduce you to your new best friend: a Bash script that'll make user management a breeze!

#### Script Breakdown

   ```#!/bin/bash
   declare -a users
   declare -a groups
   ```
   The script starts with a shebang (`#!/bin/bash`) to specify the interpreter. It then declares two arrays, `users` and `groups`, to hold user and group data.

2. **Argument Check**
   ```bash
   if [[ $# -ne 1 ]]; then
     echo "Usage: $0 <input_file>"
     exit 1
   fi
   
   input_file="$1"
   echo "Reading input file: $input_file"
   ```
   The script checks and confirm that the script is run is run with exactly one argument (the input file). Otherwise, the exit code 1 is triggered which which indicates failure. The input file is then assigned to the variable `input_file`.

3. **Reading the Input File**
   ```bash
   function read_input() {
     local file="$1"
   
     if [[ ! -f "$file" ]]; then
       echo "File not found!"
       return 1
     fi
   
     while IFS= read -r line; 
     do
       user=$(echo "$line" | cut -d';' -f1)
       groups_list=$(echo "$line" | cut -d';' -f2 | tr -d '[:space:]')
       users+=("$user")
       groups+=("$groups_list")
     done < "$file"
   }
   
   read_input "$input_file"
   ```
   The `read_input` function reads the input file line by line. Each line read is expected to contain a username and a comma-separated(delimiter) list of groups, separated by a semicolon. The function splits each line into a user and their groups, then adds these to the respective arrays.

4. **Verification of Data**
   ```bash
   echo "Users: ${users[@]}"
   echo "Groups: ${groups[@]}"
   ```
   The script prints the `users` and `groups` arrays to verify the data read from the input file.

5. **Log and Password Files Setup**
   ```bash
   log_file="/var/log/user_management.log"
   password_file="/var/secure/user_passwords.txt"
   
   touch $log_file
   mkdir -p $(dirname $password_file)
   touch $password_file

   ```
   The script sets up paths for a log file and a password file. It creates these files and their parent directories if they do not exist.

6. **User and Group Management**
   ```bash
   for (( i = 0; i < ${#users[@]}; i++ )); do
     user="${users[$i]}"
     user_groups="${groups[$i]}"
     if id "$user" &>/dev/null; then
       echo "User $user already exists, Skipped" | tee -a "$log_file"
     else
       # Create user
       useradd -m -s /bin/bash "$user"
       if [[ $? -ne 0 ]]; then
         echo "Failed to create user $user" | tee -a "$log_file"
         exit 1
       fi
       echo "User $user created" | tee -a "$log_file"
   
       password=$(openssl rand -base64 50 | tr -dc 'A-Za-z0-9!?%=' | head -c 10)
       echo "$user:$password" | chpasswd
       if [[ $? -ne 0 ]]; then
         echo "Failed to set password for $user" | tee -a "$log_file"
         exit 1
       fi
       echo "Password for $user set" | tee -a "$log_file"
       echo "$user:$password" >> "$password_file"
   
       if grep -q "^$user:" /etc/group; then
         echo "Personal group $user already exists" | tee -a "$log_file"
       else
         echo "Personal group $user does not exist, creating $user" | tee -a "$log_file"
         groupadd "$user"
         if [[ $? -ne 0 ]]; then
           echo "Failed to create personal group $user" | tee -a "$log_file"
           exit 1
         fi
       fi
   
       usermod -aG "$user" "$user"
       if [[ $? -ne 0 ]]; then
         echo "Failed to add $user to $user group" | tee -a "$log_file"
         exit 1
       fi
       echo "Added $user to $user group" | tee -a "$log_file"
   
       for group in $(echo "$user_groups" | tr ',' '\n'); do
         if grep -q "^$group:" /etc/group; then
           echo "Group $group already exists" | tee -a "$log_file"
         else
           echo "Group $group does not exist, creating $group" | tee -a "$log_file"
           groupadd "$group"
           if [[ $? -ne 0 ]]; then
             echo "Failed to create group $group" | tee -a "$log_file"
             exit 1
           fi
         fi
   
         usermod -aG "$group" "$user"
         if [[ $? -ne 0 ]]; then
           echo "Failed to add $user to $group group" | tee -a "$log_file"
           exit 1
         fi
         echo "Added $user to $group group" | tee -a "$log_file"
       done
     fi
   done
   ```
   The main loop iterates over the `users` and `groups` arrays. For each user:
   - If the user already exists, it logs and skips to the next user.
   - If the user does not exist, it creates the user, sets a password, logs the details, and creates a personal group if it does not exist.
   - The user is added to their personal group and any additional groups specified.
   
This script provides a comprehensive solution for automating the management of users and groups, ensuring consistent and secure setups based on predefined input data.