Automated User Management Script for Linux Systems
Published: 2024-07-03 20:46:32

Nowadays managing user accounts properly is extremely important for SysOps professionals working in dynamic IT setups. 
The pro of user provisioning is that it saves time, ensures consistency , security across systems  and improve efficiency since much of the process can be automated.

In this article, we will discuss about bash script and how to create a bash script that can be used for creating and managing accounts of users on Linux servers.

In this article we will be writing a script which that reads a text file containing the employee’s usernames and group names, where each line is formatted as "user;groups".

This script will 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, it will store the generated passwords securely in _/var/secure/user_passwords.txt_.
we will ensure error handling for scenarios like existing users by the script.

- Each User will 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 ";"
For example;

1. light; sudo,dev,www-data
2. idimma; sudo
3. mayowa; dev,www-data

Where light is username and groups are sudo, dev, www-data
Firstly,
```
#!/bin/bash
# Check if script is run as root
if [ "$EUID" -ne 0 ]; then
  echo "Please run as root"
  exit 1
fi
```
The #!/bin/bash line at the beginning of a script is known as the shebang. This shebang line tells the operating system which interpreter to use to execute the script. In this case, it specifies the Bash shell as the interpreter.

The line if [ "$EUID" -ne 0 ]; checks if the script is being run as root. The EUID (Effective User ID) is used to determine the privileges of the executing process. The -ne operator means "not equal." Since the root user has an ID of 0, this condition checks if the current user is not root. If true, it prompts to run the script as root and exits.

Next;

```
# Check if the input file is provided
if [ -z "$1" ]; then
  echo "Usage: bash create_users.sh <name-of-text-file>"
  exit 1
fi
```
The script checks if a positional argument is provided. If not, it exits with a status of 1 and displays the message: "Usage: bash create_user.sh <name-of-text-file>," prompting the user to provide the correct argument.

_The -z is a string value which means value has a length of zero_ and _"$1" indicate the first parameter after the script name($0)_ which is assigned a variable name INPUT_FILE. So it checks if the first positional parameter is empty.

Next;
```
INPUT_FILE="$1"
LOG_FILE="/var/log/user_management.log"
PASSWORD_FILE="/var/secure/user_passwords.txt"

# Ensure log and password files exist and have the correct permissions
touch $LOG_FILE
chmod 644 $LOG_FILE

mkdir -p /var/secure
touch $PASSWORD_FILE
chmod 600 $PASSWORD_FILE
```
We will create the directory /var/secure and the file user_password.txt in it to securely store user passwords with permissions set to "600" (read and write only for the owner). Additionally, we will create the file management.log in the /var/log directory to log all events.

The first positional parameter($1) is assigned INPUT_FILE as variable

Next;
```
# Function to generate random password
generate_password() {
  openssl rand -base64 12
}
```
The OpenSSL rand command will be used to generate a cryptographic password that is base64 encoded (strong and resistant as it contains letters, numbers, and characters). This function will generate the password, which will be called in the script.

Next;
```
# Process the input file
while IFS=';' read -r username groups; do
  # Create personal group for the user
  if ! getent group "$username" &>/dev/null; then
    groupadd "$username"
    echo "Created group $username" | tee -a $LOG_FILE
  fi
```
Let's process the input file;

> IFS means Internal Field Separator; this is an environment variable which define a list of characters the Bash shell uses as field separators. These include space, tab, newline.

Use the while condition to read the username and group taking note of the separators by the IFS.

We will create a personal group for the user but before then we will check the system group database (/etc/group) using the _getent_ command to ensure the group is not present.

The negate operator (!) is used to reverse the outcome of an expression. In this case, if the $group does not exist, the expression with ! will evaluate to true. This condition triggers the groupadd command to create the group if it doesn't already exist.

```
# Check if user already exists
  if id "$username" &>/dev/null; then
    echo "User $username already exists. Skipping..." | tee -a $LOG_FILE
    continue
  fi
```
If user already exist then our shell script will throw an error message indicating that user exist but we want to redirect such output( standard error or output) to the _/dev/null_ and the tee reads the output and save it silently in the $LOG_FILE.

We then use the continue to create user if user does not exist.

```
# Create user and personal group
  useradd -m -s /bin/bash -g "$username" "$username"
  if [ $? -eq 0 ]; then
    echo "Created user $username with a personal group $username" | tee -a $LOG_FILE
  else
    echo "Failed to create user $username" | tee -a $LOG_FILE
    continue
  fi
```
Let's add create user and add to the personal group using the popular command _useradd_ and use the -m(to add a home directory for the user, -s (to set the shell to /bin/bash).

If the user is created and added to the personal group successfully this make the exit status ($?) equal zero (0) and it print the success message "Created user $username with a personal group $username" to the $LOG_FILE and if not it execute the else statement.

Next;
```
 # Generate password and set it for the user
  password=$(generate_password)
  echo "$username:$password" | chpasswd
  if [ $? -eq 0 ]; then
    echo "$username,$password" >> $PASSWORD_FILE
    echo "Set password for $username" | tee -a $LOG_FILE
  else
    echo "Failed to set password for $username" | tee -a $LOG_FILE
  fi
```
Let's call the function to generate the password and set password for the user using chpasswd (change password) , write the username,password into the $PASSWORD_FILE and log it.

> chpasswd is designed to process multiple username and password pairs from standard input (usually via a pipe | or a redirection <)
.

Next,
```
# Create additional groups if specified
  if [ -n "$groups" ]; then
    IFS=',' read -ra group_array <<< "$groups"
    for group in "${group_array[@]}"; do
      # Create group if it doesn't exist
      if ! getent group "$group" &>/dev/null; then
        groupadd "$group"
        echo "Created group $group" | tee -a $LOG_FILE
      fi
  fi
```
we will be creating other group which user will be by passing the $groups as an array and iterate  over it by "${group_array[@]}" where "@" insinuate every character.

The character -n is also similar to the -z only that it describe value which length is greater than zero

We will check the system group database (/etc/group) using the getent command but will add a negate operator (!) which will negate the expression and makes it True, if the $group does not exist thereby causing it to create the group if it doesn't exist using the groupadd command as previously discussed.

Next;
```
usermod -aG "$group" "$username"
      if [ $? -eq 0 ]; then
        echo "Added $username to group $group" | tee -a $LOG_FILE
      else
        echo "Failed to add $username to group $group" | tee -a $LOG_FILE
      fi
    done
  fi
```
we then add the user to group using the usermod -aG command
Finally,

```
done < "$INPUT_FILE"
echo "User creation process completed." | tee -a $LOG_FILE
```
we will close our while  loop condition and pass the $INPUT_FILE to read lines from it.
Create a directory, touch a file named create.sh (shell script) in the directory and make the file executable; 

```
sudo mkdir -p ~/bash-script
sudo chmod +x ~/bash-script/create_users.sh
```
open the create and paste this script;

```
#!/bin/bash
#check if script is run as root
if [ "$EUID" -ne 0 ]; then
  echo "Please run as root"
  exit 1
fi

# Check if the input file is provided
if [ -z "$1" ]; then
  echo "Usage: bash create_users.sh <name-of-text-file>"
  exit 1
fi

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

# Ensure log and password files exist and have the correct permissions
touch $LOG_FILE
chmod 644 $LOG_FILE

mkdir -p /var/secure
touch $PASSWORD_FILE
chmod 600 $PASSWORD_FILE

# Function to generate random password
generate_password() {
  openssl rand -base64 12
}

# Process the input file
while IFS=';' read -r username groups; do
  # Create personal group for the user
  if ! getent group "$username" &>/dev/null; then
    groupadd "$username"
    echo "Created group $username" | tee -a $LOG_FILE
  fi

  # Check if user already exists
  if id "$username" &>/dev/null; then
    echo "User $username already exists. Skipping..." | tee -a $LOG_FILE
    continue
  fi

  # Create user and personal group
  useradd -m -s /bin/bash -g "$username" "$username"
  if [ $? -eq 0 ]; then
    echo "Created user $username with a personal group $username" | tee -a $LOG_FILE
  else
    echo "Failed to create user $username" | tee -a $LOG_FILE
    continue
  fi

  # Generate password and set it for the user
  password=$(generate_password)
  echo "$username:$password" | chpasswd
  if [ $? -eq 0 ]; then
    echo "$username,$password" >> $PASSWORD_FILE
    echo "Set password for $username" | tee -a $LOG_FILE
  else
    echo "Failed to set password for $username" | tee -a $LOG_FILE
  fi

  # Create additional groups if specified
  if [ -n "$groups" ]; then
    IFS=',' read -ra group_array <<< "$groups"
    for group in "${group_array[@]}"; do
      # Create group if it doesn't exist
      if ! getent group "$group" &>/dev/null; then
        groupadd "$group"
        echo "Created group $group" | tee -a $LOG_FILE
      fi

      usermod -aG "$group" "$username"
      if [ $? -eq 0 ]; then
        echo "Added $username to group $group" | tee -a $LOG_FILE
      else
        echo "Failed to add $username to group $group" | tee -a $LOG_FILE
      fi
    done
  fi
done < "$INPUT_FILE"

echo "User creation process completed." | tee -a $LOG_FILE
```
Create a file (input_file.txt) containing username;groups

```
light; sudo,dev,www-data
idimma; sudo
mayowa; dev,www-data
```
Run the script and pass the input_file.txt as argument.

Thank you for reading, to learn more kindly join the HNG internship programme to get your tech skill upgraded and land you dream job.
Follow this link
https://hng.tech/internship, 
https://hng.tech/hire



















































































hsh