Complete Script Guide: Creating New Admin Users in Linux

Key takeaways

  • Automates admin user creation: Streamlines the process of adding new admin users in Linux environments.
  • Enhances efficiency and accuracy: Reduces manual efforts and minimizes the risk of human error.
  • Script flexibility: Adaptable to various needs, supporting different user, password, and group options.
  • Security focused: Incorporates password encryption and requires root privileges, prioritizing security.
  • Versatile usage: Suitable for both individual and MSP managing multiple Linux systems.
  • Comparison with traditional methods: Offers a more cohesive and scalable solution compared to manual commands or GUI tools.
  • FAQs addressed: Clarifies security, bulk operations, and compatibility concerns.
  • Security implications: Stresses the importance of proper privilege management and script usage auditing.
  • Best practice recommendations: Advises testing, logging, and regular account reviews.
  • NinjaOne integration: Highlights how such scripts complement broader IT management platforms like NinjaOne.

Administering Linux systems effectively often requires the creation and management of user accounts, especially those with administrative privileges. Understanding the nuances of this process is crucial for system administrators and IT professionals. The script in focus today addresses this need by providing an efficient way to add new admin users in Linux environments.

Background

In the world of IT, managing user accounts is a fundamental task. This script is particularly relevant for IT professionals and Managed Service Providers (MSPs) who frequently handle multiple Linux servers or workstations. The automation of admin user creation not only saves time but also reduces the likelihood of human error. Its importance cannot be understated in scenarios where prompt and secure user management is critical.

The script:

#!/usr/bin/env bash
#
# Description: Create a new admin user for Linux, by adding the user to the sudo group.
# By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
# Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
# Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
# Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
# Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
# Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
# Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
# EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).

# Usage: [-u|--user <arg>] [-p|--pass <arg>] [-g|--group <arg>] [-d|--disable <arg>] [-h|--help]
# -u, --user: User Name for new user account. (no default)
# -p, --pass: Password for new user account. (no default)
# -g, --group: Name of group to add the new user account to. (default 'sudo')
# -d, --disable: Date to disable account. (no default)
# -h, --help: Prints help

# # When called, the process ends.
# Args:
# 	$1: The exit message (print to stderr)
# 	$2: The exit code (default is 1)
# if env var _PRINT_HELP is set to 'yes', the usage is print to stderr (prior to $1)
# Example:
# 	test -f "$_arg_infile" || _PRINT_HELP=yes die "Can't continue, have to supply file as an argument, got '$_arg_infile'" 4
die() {
    local _ret="${2:-1}"
    test "${_PRINT_HELP:-no}" = yes && print_help >&2
    echo "$1" >&2
    exit "${_ret}"
}

# Function that evaluates whether a value passed to it begins by a character
# that is a short option of an argument the script knows about.
# This is required in order to support getopts-like short options grouping.
begins_with_short_option() {
    local first_option all_short_options='uph'
    first_option="${1:0:1}"
    test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}
_arg_user=
_arg_pass=
_arg_group="sudo"
_arg_disable=

if [[ -n "${username}" ]]; then
    _arg_user=$username
fi
if [[ -n "${password}" ]]; then
    _arg_pass=$password
fi
if [[ -n "${group}" ]] && [[ "${group}" != "null" ]]; then
    _arg_group=$group
fi
if [[ -n "${disableAfterDate}" ]] && [[ "${disableAfterDate}" != "null" ]]; then
    _arg_disable=$(date -d "$disableAfterDate" +'%Y-%m-%d')
fi

# Function that prints general usage of the script.
# This is useful if users asks for it, or if there is an argument parsing error (unexpected / spurious arguments)
# and it makes sense to remind the user how the script is supposed to be called.
print_help() {
    printf '%s\n' "Create a new admin user."
    printf 'Usage: %s [-u|--user <arg>] [-p|--pass <arg>] [-g|--group <arg>] [-e|--enable <arg>] [-d|--disable <arg>] [-h|--help]\n' "$0"
    printf '\t%s\n' "-u, --user: User Name for new user account. (no default)"
    printf '\t%s\n' "-p, --pass: Password for new user account. (no default)"
    printf '\t%s\n' "-g, --group: Name of group to add the new user account to. (default 'sudo')"
    printf '\t%s\n' "-d, --disable: Date to disable account. (no default)"
    printf '\t%s\n' "-h, --help: Prints help"
}

# The parsing of the command-line
parse_commandline() {
    while test $# -gt 0; do
        _key="$1"
        case "$_key" in
        # We support whitespace as a delimiter between option argument and its value.
        # Therefore, we expect the --user or -u value.
        # so we watch for --user and -u.
        # Since we know that we got the long or short option,
        # we just reach out for the next argument to get the value.
        -u | --user)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_user="$2"
            shift
            ;;
        # We support the = as a delimiter between option argument and its value.
        # Therefore, we expect --user=value, so we watch for --user=*
        # For whatever we get, we strip '--user=' using the ${var##--user=} notation
        # to get the argument value
        --user=*)
            _arg_user="${_key##--user=}"
            ;;
        # We support getopts-style short arguments grouping,
        # so as -u accepts value, we allow it to be appended to it, so we watch for -u*
        # and we strip the leading -u from the argument string using the ${var##-u} notation.
        -u*)
            _arg_user="${_key##-u}"
            ;;
        # See the comment of option '--user' to see what's going on here - principle is the same.
        -p | --pass)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_pass="$2"
            shift
            ;;
        # See the comment of option '--user=' to see what's going on here - principle is the same.
        --pass=*)
            _arg_pass="${_key##--pass=}"
            ;;
        # See the comment of option '-u' to see what's going on here - principle is the same.
        -p*)
            _arg_pass="${_key##-p}"
            ;;
        # See the comment of option '--user' to see what's going on here - principle is the same.
        -g | --group)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_group="$2"
            shift
            ;;
        # See the comment of option '--user=' to see what's going on here - principle is the same.
        --group=*)
            _arg_group="${_key##--group=}"
            ;;
        # See the comment of option '-u' to see what's going on here - principle is the same.
        -g*)
            _arg_group="${_key##-g}"
            ;;
        # See the comment of option '--user' to see what's going on here - principle is the same.
        -d | --disable)
            test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
            _arg_disable="$2"
            shift
            ;;
        # See the comment of option '--user=' to see what's going on here - principle is the same.
        --disable=*)
            _arg_disable="${_key##--disable=}"
            ;;
        # See the comment of option '-u' to see what's going on here - principle is the same.
        -d*)
            _arg_disable="${_key##-d}"
            ;;
        # The help argument doesn't accept a value,
        # we expect the --help or -h, so we watch for them.
        -h | --help)
            print_help
            exit 0
            ;;
        # We support getopts-style short arguments clustering,
        # so as -h doesn't accept value, other short options may be appended to it, so we watch for -h*.
        # After stripping the leading -h from the argument, we have to make sure
        # that the first character that follows corresponds to a short option.
        -h*)
            print_help
            exit 0
            ;;
        *)
            _PRINT_HELP=yes die "FATAL ERROR: Got an unexpected argument '$1'" 1
            ;;
        esac
        shift
    done
}

parse_commandline "$@"

if [[ -z "${_arg_user}" ]]; then
    die "FATAL ERROR: User Name is required. '$_arg_user'" 1
fi

if [[ -z "${_arg_pass}" ]]; then
    die "FATAL ERROR: Password is required. '$_arg_pass'" 1
fi

if [ "$(id -u)" -eq 0 ]; then
    if grep -E "^$_arg_user" /etc/passwd >/dev/null; then
        # User already exists, add them to the group
        echo "$_arg_user exists!"
        if usermod -aG "$_arg_group" "$_arg_user"; then
            echo "User($_arg_user) has been added to $_arg_group group!"
        else
            echo "Failed to add a user to $_arg_group group!"
            exit 1
        fi
    else
        pass=$(perl -e 'print crypt($ARGV[0], "password")' "$_arg_pass")
        if useradd -m -p "$pass" "$_arg_user"; then
            echo "User($_arg_user) has been added to system!"
        else
            echo "Failed to add a user!"
            exit 1
        fi
        if usermod -aG "$_arg_group" "$_arg_user"; then
            echo "User($_arg_user) has been added to $_arg_group group!"
        else
            echo "Failed to add a user to $_arg_group group!"
            exit 1
        fi
    fi
    if [[ -n "${_arg_disable}" ]]; then
        # Expire the user after date
        usermod -e "$_arg_disable" "$_arg_user"
    fi

else
    echo "Only root may add a user to the system."
    exit 2
fi

 

Access 300+ scripts in the NinjaOne Dojo

Get Access

Detailed breakdown

Script functionality:

  • Environment setup: The script begins with a shebang line (#!/usr/bin/env bash), setting up the environment to use Bash as the scripting language.
  • Description and usage: It includes comments explaining its purpose – to create a new admin user by adding them to a group, typically ‘sudo’.
  • Function definitions:
    • die(): Handles exit scenarios, showing error messages when needed.
    • begins_with_short_option(): Helps in parsing command-line options. \
    • print_help(): Displays usage instructions.
  • Variable initialization: Variables like _arg_user, _arg_pass, _arg_group, and _arg_disable are initialized.
  • Parsing command-line arguments: The parse_commandline() function iterates over arguments to set user, password, group, and disable date.
  • User creation logic:
    • Checks if the user exists.
    • If not, creates a new user and adds them to the specified group.
    • Optionally sets a disable date for the user account.
  • Root privilege check: Ensures the script is run by a user with root privileges, a necessary step for creating and modifying user accounts.

Potential use cases

Consider an MSP managing a fleet of Linux servers for a client. They receive a request to quickly onboard a new team of developers needing admin access. Using this script, the MSP can efficiently create individual admin accounts, ensuring each team member gets appropriate access without manual intervention, saving time and minimizing errors.

Comparisons

Traditionally, creating a new admin user on Linux involves multiple manual commands (useradd, passwd, usermod). This script automates these steps in a single, cohesive process. Unlike GUI-based user management tools, this script can be integrated into larger automation workflows, making it more flexible and scalable.

FAQs

  • How does this script secure the password?
    • It uses perl to encrypt the password before creating the user, enhancing security.
  • Can the script handle bulk user creation?
    • As written, it’s designed for single-user creation. However, it can be modified for bulk operations.
  • Is it compatible with all Linux distributions?
    • The script should work on most Linux distributions that have the Bash shell and standard user management utilities.

Implications

While this script is a powerful tool for system administrators, it’s essential to be aware of its security implications. Properly managing user privileges is crucial for system security. Misuse or errors in the script could inadvertently grant excessive permissions.

Recommendations

  • Always test the script in a non-production environment first.
  • Implement logging to track the script’s usage and output.
  • Regularly review and audit user accounts created by the script.

Final thoughts

In conclusion, this script exemplifies how automation can streamline administrative tasks in Linux environments. For broader IT management and automation, solutions like NinjaOne provide the necessary tools and infrastructure, offering robust support for tasks like these, ensuring efficiency and security in managing IT environments.

Next Steps

Building an efficient and effective IT team requires a centralized solution that acts as your core service deliver tool. NinjaOne enables IT teams to monitor, manage, secure, and support all their devices, wherever they are, without the need for complex on-premises infrastructure.

Learn more about NinjaOne Remote Script Deployment, check out a live tour, or start your free trial of the NinjaOne platform.

Categories:

You might also like

×

See NinjaOne in action!

By submitting this form, I accept NinjaOne's privacy policy.

NinjaOne Terms & Conditions

By clicking the “I Accept” button below, you indicate your acceptance of the following legal terms as well as our Terms of Use:

  • Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
  • Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
  • Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library belonging to or under the control of any other software provider.
  • Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
  • Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
  • Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
  • EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).