Smart Group to identify user w administrative privileges .

tharr00
New Contributor II

Hello'
Objective: Create smart group to report on systems that users have administrative rights.
I created the extension attribute via script. It is accurately reporting accounts that have administrative rights. The problem is when I create the logic for the smart group there is no way for me to differentiate/exclude from known admin accounts. There are three possible admin accounts that may exist on a given system. When I create the criteria logic I make an entry for each that "is not" admdsk, and/or "is not" mbadmin and finish with "is not" blank. tried every possible combination of and's an or's with and with out parentheeses to no avail. I'm pretty sure this will require a appended script that will exclude the known accounts before output. I'm guessing this is an issue because the script output is multiple account name separated by a space. Here is the existing script that makes the extension attribute output.

!/bin/bash

Script to detect if a computer has a local admin account on it with an UID of above 500

Initialize array

list=()

generate user list of users with UID greater than 500

for username in $(dscl . list /Users UniqueID | awk '$2 > 500 { print $1 }'); do

Checks to see which usernames are reported as being admins. The

check is running dsmemberutil's check membership and listing the

accounts that are being reported as admin users. Actual check is

for accounts that are NOT not an admin (i.e. not standard users.)

if [[ $(dsmemberutil checkmembership -U "${username}" -G admin) != not ]]; then # Any reported accounts are added to the array list list+=("${username}") fi
done

Prints the array's list contents

echo "result>${list[@]}</result"

1 ACCEPTED SOLUTION

sean
Valued Contributor

Guess you don't make your admins hidden accounts, even though that is what your original script is based upon (user id greater than 500). You can specify an array of known admin accounts and check against that instead. Based on your output above, this should just return thar00. Change the array to account for any known admins you wish to exclude from the result.

You could also add a check at the end and if the array is empty specify the output.

#!/bin/bash

#Script to detect if a computer has unknown local admin accounts
#Initialize array
declare -a admin_list=()
# Declare known admins
declare -a known_admins=('root' 'dsadmin')

# Add unknown admins users to array
function add_admins
{
        while [ $# -gt 0 ]
        do
                # Assume unknown until otherwise proven
                it_admin="FALSE"
                # Check admin aginst list of known admins
                # If known do not add to list
                for each_admin in "${known_admins[@]}"
                do
                        if [[ "$each_admin" == "$1" ]]
                        then
                                it_admin="TRUE"
                                break
                        fi
                done

                # If not known now add to list
                if [[ "$it_admin" == "FALSE" ]]
                then
                        admin_list+=($1)
                fi
                shift
        done
}

# Get admin user list and pass to function
add_admins `dscl . read /Groups/admin GroupMembership | cut -d ":" -f 2`

# Prints the array's list contents
echo "<result>$(printf '%s
' "${admin_list[@]}")</result>"

exit 0

View solution in original post

12 REPLIES 12

mm2270
Legendary Contributor III

First thing is, please enclose your script in the script tags here so we can actually see the formatting. That's the button with the >_ icon on it.

Second, to solve the issue, you can use the printf command to print the array so it puts each name on its own line.

Here is your script with the script formatting in place and with the printf command included in the result output.

#!/bin/bash

#Script to detect if a computer has a local admin account on it with an UID of above 500
#Initialize array
list=()

#generate user list of users with UID greater than 500
for username in $(dscl . list /Users UniqueID | awk '$2 > 500 { print $1 }'); do

# Checks to see which usernames are reported as being admins.
# The check is running dsmemberutil's check membership and listing the accounts that are being reported as admin users.
# Actual check is for accounts that are NOT not an admin (i.e. not standard users.)
    if [[ $(dsmemberutil checkmembership -U "${username}" -G admin) != not ]]; then
        # Any reported accounts are added to the array list
        list+=("${username}")
    fi
done

# Prints the array's list contents
echo "<result>$(printf '%s
' "${list[@]}")</result>"

Last thing is, I'm not completely certain if your test condition will return the results you're looking for. Typically the != syntax looks for an exact match or in this case, non match. Since the dsmemberutil command isn't returning just "not" as its result, it may end up pulling in accounts that are in fact not admins. I haven't really tested your script to see about that though. If you find its not working as expected, you can change the line to look like this, which should work

if [[ ! $(dsmemberutil checkmembership -U "${username}" -G admin) =~ not ]]; then

tharr00
New Contributor II

First, thank you for the direction regarding the tags.
OK I left the old script in place for "User Admins" attribute and created the EA "User Admins v2" with your script. There are three accounts on this system, the test account is a standard account. The output was identical whether I used

#if [[ $(dsmemberutil checkmembership -U "${username}" -G admin) != not ]]; then

OR

#if [[ ! $(dsmemberutil checkmembership -U "${username}" -G admin) =~ not ]]; then

here is the outputbade602878704c8c8929249ec8493307

sean
Valued Contributor

I'd probably do it the other way around. Rather than go through every user and work out what their UID is and then check their membership, I'd get a list of the local admins and then remove those that don't have a UID greater than 500

#!/bin/bash

#Script to detect if a computer has a local admin account on it with an UID of above 500
#Initialize array
declare -a admin_list=()

# Test admin users and add users with id greater than 500 to array
function test_for_admins
{
        while [ $# -gt 0 ]
        do
                if [ `id -u $1` -gt 500 ]
                then
                        admin_list+=($1)
                fi
                shift
        done
}

# Get admin user list and pass to function
test_for_admins `dscl . read /Groups/admin GroupMembership | cut -d ":" -f 2`

# Prints the array's list contents
echo "<result>$(printf '%s
' "${admin_list[@]}")</result>"

exit 0

tharr00
New Contributor II

Thank you sean, We are getting closer, but I am still not able to get the Smart Computer Group logic to exclude known accounts. Excuse my script illiteracy, but would it be possible for the output to be filtered to exclude variables (known accounts) ? Resulting in just a users account (with admin) or a blank output (no other account with admin) ? Here is the current output40f33ab3d38d47bcb234502c6d006e96

sean
Valued Contributor

Guess you don't make your admins hidden accounts, even though that is what your original script is based upon (user id greater than 500). You can specify an array of known admin accounts and check against that instead. Based on your output above, this should just return thar00. Change the array to account for any known admins you wish to exclude from the result.

You could also add a check at the end and if the array is empty specify the output.

#!/bin/bash

#Script to detect if a computer has unknown local admin accounts
#Initialize array
declare -a admin_list=()
# Declare known admins
declare -a known_admins=('root' 'dsadmin')

# Add unknown admins users to array
function add_admins
{
        while [ $# -gt 0 ]
        do
                # Assume unknown until otherwise proven
                it_admin="FALSE"
                # Check admin aginst list of known admins
                # If known do not add to list
                for each_admin in "${known_admins[@]}"
                do
                        if [[ "$each_admin" == "$1" ]]
                        then
                                it_admin="TRUE"
                                break
                        fi
                done

                # If not known now add to list
                if [[ "$it_admin" == "FALSE" ]]
                then
                        admin_list+=($1)
                fi
                shift
        done
}

# Get admin user list and pass to function
add_admins `dscl . read /Groups/admin GroupMembership | cut -d ":" -f 2`

# Prints the array's list contents
echo "<result>$(printf '%s
' "${admin_list[@]}")</result>"

exit 0

tharr00
New Contributor II

Thank you Sean, this works well appears that I only have to set my smart group to Admin Users "is not" blank.

sean
Valued Contributor

Cool. You may want to mark it resolved for anyone else that may search in the future.

tharr00
New Contributor II
 

bentoms
Release Candidate Programs Tester

Just posting my version, slightly different use case... but might be handy for some.

sean
Valued Contributor

@bentoms Careful with your script. You may get false positives. Eg.

#!/bin/bash

#What if the user is called David Min and is not a local account admin

adminGroupMembership="root admin"
loggedInUser=dmin

if [[ $adminGroupMembership =~ "$loggedInUser" ]]
then
        echo "User is admin"
else
        echo "User is not admin"
fi

exit 0

This is why I used an array and did exact matches.

phillnz
New Contributor II

This script it working well for me, however, I'd like to create a smart group based on this EA. At the moment, if it finds no known users, the result is blank. The problem with this is that I can't report on a blank EA field. Is there to modify this, so if no users were found it prints something like "No Admin Users"?

StevenNation
New Contributor

In response to @phillnz, I tried editing the original script by sean to print an output if the admin_list array is empty. I'm fairly novice at this but it seems to work. Feel free to suggest any improvements.

#!/bin/bash

#Script to detect if a computer has unknown local admin accounts
#Initialize array
declare -a admin_list=()
# Declare known admins
declare -a known_admins=('root' 'dsadmin')

# Add unknown admins users to array
function add_admins
{
        while [ $# -gt 0 ]
        do
                # Assume unknown until otherwise proven
                it_admin="FALSE"
                # Check admin aginst list of known admins
                # If known do not add to list
                for each_admin in "${known_admins[@]}"
                do
                        if [[ "$each_admin" == "$1" ]]
                        then
                                it_admin="TRUE"
                                break
                        fi
                done

                # If not known now add to list
                if [[ "$it_admin" == "FALSE" ]]
                then
                        admin_list+=($1)
                fi
                shift
        done
}

# Get admin user list and pass to function
add_admins `dscl . read /Groups/admin GroupMembership | cut -d ":" -f 2`

# Prints the array's list contents
if [[ $admin_list == "" ]]
then 
        echo "No unknown admin users" 

else 
        echo "<result>$(printf '%s
' "${admin_list[@]}")</result>"
fi

exit 0