Little scripting help (checking variables against array in bash)

bentoms
Release Candidate Programs Tester

Hi guys,

I'm writing some scripts for Sophos SafeGuard deployment through Casper.

Part of the script is a for loop that checks the variables in a array & looks to see if the currently logged in user has a safeguard account..

When it finds the user I get the following error:

/private/var/folders/oB/oBElW1WCHGS4eJKR5FXfNp1IAMU/Cleanup At Startup/Sophos Safeguard User Setup-320768112.682.sh: line 31: ((: GreyUK
btoms: syntax error in expression (error token is "btoms")

I'm sure the solution is simple.. Just need to be pointed in the right direction

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

22 REPLIES 22

Not applicable

We'll need to see the script...

bentoms
Release Candidate Programs Tester

Here you go!

#!/bin/sh

# HARDCODED VALUES ARE SET HERE
loggedInUser=""
SGAdmin=""
SGAdminPassword=""

# CHECK TO SEE IF A VALUE WAS PASSED IN PARAMETER 4 AND, IF SO, ASSIGN TO
"sgUsername"
if [ "$4" != "" ] && [ "$loggedInUser" == "" ];then loggedInUser=$4
fi

# CHECK TO SEE IF A VALUE WAS PASSED IN PARAMETER 5 AND, IF SO, ASSIGN TO
"sgPassword"
if [ "$5" != "" ] && [ "$SGAdmin" == "" ];then SGAdmin=$5
fi

# CHECK TO SEE IF A VALUE WAS PASSED IN PARAMETER 6 AND, IF SO, ASSIGN TO
"localAdmin"
if [ "$6" != "" ] && [ "$SGAdminPassword" == "" ];then SGAdminPassword=$6
fi

###########################################################################
#########################
# # SCRIPT CONTENTS - DO NOT MODIFY BELOW THIS LINE
#
###########################################################################
#########################

#Get the logged in users username
loggedInUser=/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'

#Check to see if the logged in user is a network account
accountType=`dscl . -read /Users/$loggedInUser | ?grep UniqueID | cut -c
11-`

#List all safeguard users
SafeGuardUsers=`sgadmin --list-users --authenticate-user "$SGAdmin"
--authenticate-password "$SGAdminPassword" | cut -f2 -d "|" | cut -c 8- |
sed 's/ //g'`

echo "$SafeGuardUsers"

#If the logged in user is a network account
if (( "$accountType" > 1000 )); then echo "Account $loggedInUser is a Network Account..." #Check to see if the logged in network account has a safeguard user
created for i in `sgadmin --list-users --authenticate-user "$SGAdmin"
--authenticate-password "$SGAdminPassword" | cut -f2 -d "|" | cut -c 8-` do if (("$loggedInUser" == "$SafeGuardUsers")); then echo "No Safeguard account for $loggedInUser..." UserPassword=`/usr/bin/osascript << EOT set newIcon to (POSIX file
"/Applications/sgui.app/Contents/Resources/change_password.icns") as alias tell application "Finder" display dialog "Please enter your password below:" buttons {"OK"}
default answer "" with icon newIcon with hidden answer set result to text returned of result end tell #EOT` echo "User Password entered" /usr/bin/sgadmin --add-user --type user --user "$loggedInUser"
--password "$UserPassword" --confirm-password "$UserPassword"
--authenticate-user "$SGAdmin" --authenticate-password "$SGAdminPassword" else echo "Safeguard account already exists for $loggedInUser..." break fi done
else echo "Account $loggedInUser is a local account exiting Safeguard
setup..."
fi

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

Not applicable

Unfortunately, I can't seem to match that line number properly. The only thing I can think of is that you need spaces around the (( and )). I don't see any other syntax errors here (though I'm not convinced it would recognize #EOT` properly...).

You might also want to think about security implications of sending passwords around the script like that. A command like "ps auxwww" (run as any user) can collect the full command line of all running processes...
Unfortunately, I am not familiar enough with SafeGuard to be able to discuss how best to address the risks as effectively as possible; perhaps someone else on this list can help with that.

bentoms
Release Candidate Programs Tester

Thanks I'll try the brackets.

The admin account is just for safeguard & we can change it from jss if it gets comprised.

Regards,

Ben Toms

bentoms
Release Candidate Programs Tester

Still not working :(

Basically... SafeGuardUsers returns a list of users like:

Btoms
GreyUK

I need the logged in users username to be checked against the list..

My script below gives false negatives.. Any idea?

if (( "$loggedInUser" == "${SafeGuardUsers[*]}" )); then echo "SafeGuard account already exists for $loggedInUser..." break else echo "No SafeGuard account for $loggedInUser..."

fi

Script below......

#!/bin/sh

# HARDCODED VALUES ARE SET HERE
loggedInUser=""
SGAdmin="GreyUK"
SGAdminPassword="Password"

# CHECK TO SEE IF A VALUE WAS PASSED IN PARAMETER 4 AND, IF SO, ASSIGN TO
"sgUsername"
if [ "$4" != "" ] && [ "$loggedInUser" == "" ];then loggedInUser=$4
fi

# CHECK TO SEE IF A VALUE WAS PASSED IN PARAMETER 5 AND, IF SO, ASSIGN TO
"sgPassword"
if [ "$5" != "" ] && [ "$SGAdmin" == "" ];then SGAdmin=$5
fi

# CHECK TO SEE IF A VALUE WAS PASSED IN PARAMETER 6 AND, IF SO, ASSIGN TO
"localAdmin"
if [ "$6" != "" ] && [ "$SGAdminPassword" == "" ];then SGAdminPassword=$6
fi

###########################################################################
#########################
# # SCRIPT CONTENTS - DO NOT MODIFY BELOW THIS LINE
#
###########################################################################
#########################

#Get the logged in users username
loggedInUser=/bin/ls -l /dev/console | /usr/bin/awk '{ print $3 }'

#Check to see if the logged in user is a network account
accountType=`dscl . -read /Users/$loggedInUser | ?grep UniqueID | cut -c
11-`

#List all SafeGuard users
SafeGuardUsers=`sgadmin --list-users --authenticate-user "$SGAdmin"
--authenticate-password "$SGAdminPassword" | cut -f2 -d "|" | cut -c 8- |
sed 's/ //g' | tr -d ' '`

echo "$SafeGuardUsers"

#If the logged in user is a network account
if (( "$accountType" > 1000 )); then echo "Account $loggedInUser is a Network Account..." #Check to see if the logged in network account has a SafeGuard user
created for i in `sgadmin --list-users --authenticate-user "$SGAdmin"
--authenticate-password "$SGAdminPassword" | cut -f2 -d "|" | cut -c 8-` do if (( "$loggedInUser" == "${SafeGuardUsers[]}" )); then echo "SafeGuard account already exists for $loggedInUser..." break else echo "No SafeGuard account for $loggedInUser..." UserPassword=`/usr/bin/osascript << EOT set newIcon to (POSIX file
"/Applications/sgui.app/Contents/Resources/change_password.icns") as alias
set UserPassword21 to ""
set UserPassword2 to ""
set passwordComplexity to 0
set passwordAlpha to {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y",
"Z"}
set passwordSpecial to {"~", "!", "@", "#", "$", "%", "^", "&", "
", "(",
")", "_", "+", "-", "=", "[", "]", ">", "?", ";", ":"}
set passwordNumbers to {"1", "2", "3", "4", "5", "6", "7", "8", "9", "0"}

tell application "Finder" repeat while UserPassword21 = "" display dialog "Please enter your password below." & "

The password needs to be a minimum of 8 characters in length & must
contain at least 2 of the following 3. A capital letter, number or special
character." buttons {"OK"} default answer "" with icon newIcon with hidden
answer set UserPassword21 to text returned of result repeat while length of UserPassword21 < 8 display dialog "Password needs to be a minimum of 8 characters."
buttons {"OK"} default answer "" with icon newIcon with hidden answer set UserPassword21 to text returned of result end repeat end repeat
end tell

tell application "Finder" repeat with userPasswordChar in UserPassword21 set userPasswordChar to userPasswordChar as text considering case if userPasswordChar is in passwordAlpha or (userPasswordChar is in
passwordSpecial) or (userPasswordChar is in passwordNumbers) then set passwordComplexity to passwordComplexity + 1 end if end considering end repeat repeat while passwordComplexity < 2 display dialog "Password does not meet security requirements." & "

The password needs to be a minimum of 8 characters in length & must
contain at least 2 of the following 3. A capital letter, number or special
character." & "

Please retry." buttons {"OK"} default answer "" with icon newIcon with
hidden answer set UserPassword21 to text returned of result repeat with userPasswordChar in UserPassword21 set userPasswordChar to userPasswordChar as text considering case if userPasswordChar is in passwordAlpha or (userPasswordChar is in
passwordSpecial) or (userPasswordChar is in passwordNumbers) then set passwordComplexity to passwordComplexity + 1 end if end considering end repeat

end repeat display dialog "Please verify your password below." buttons {"OK"}
default answer "" with icon newIcon with hidden answer set UserPassword2 to text returned of result repeat while UserPassword2 is not equal to UserPassword21 considering case display dialog "Passwords do not match, please re-enter your password
below." buttons {"OK"} default answer "" with icon newIcon with hidden
answer set UserPassword2 to text returned of result end considering end repeat set UserPassword to UserPassword2
end tell
EOT` echo "User Password entered & accepted..." echo $UserPassword /usr/bin/sgadmin --add-user --type user --user "$loggedInUser"
--password "$UserPassword" --confirm-password "$UserPassword"
--authenticate-user "$SGAdmin" --authenticate-password "$SGAdminPassword" echo "SafeGuard account created for $loggedInUser..." completionMessage=`/usr/bin/osascript << EOT set newIcon to (POSIX file
"/Applications/sgui.app/Contents/Resources/change_password.icns") as alias tell application "Finder" display dialog "Your SafeGuard User account has now be setup." & "

When you next restart you will need to enter your Username & the password
you have just entered." buttons {"OK"} default button "OK" with icon
newIcon end tell` fi done
else echo "Account $loggedInUser is a local account... Exiting SafeGuard
setup..."
fi

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

jarednichols
Honored Contributor

Why not read the list of users into an array which you can then cycle
through against another array containing the list you're trying to compare
against?

j
-- Jared F. Nichols
Desktop Engineer, Client Services
Information Services Department
MIT Lincoln Laboratory
244 Wood Street
Lexington, Massachusetts 02420
781.981.5436

bentoms
Release Candidate Programs Tester

Guess I need more bash tutorials.. :(

Should I use = or == to compare to variables?

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

tlarkin
Honored Contributor

Depends on what you are comparing, but basically [[ and == is a more
robust comparison than [ and =

What exactly are you trying to do? Have the user create a username and
password for that third party product?

bentoms
Release Candidate Programs Tester

What exactly are you trying to do? Have the user create a username and password for that third party product? >> bingo

I need the below to run at login & if the user hasn't got an account in this app prompt for them to create one..

But.. After outputting this line to text: sgadmin --list-users --authenticate-user "$SGAdmin" --authenticate-password "$SGAdminPassword" | cut -f2 -d "|" | cut -c 8- | sed 's/ //g' | tr -d ' '

Turns out I'm removing all not just the trailing from the output (I've been trying to remove all whitespace & last from output)..

I think this may be the issue..

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

tlarkin
Honored Contributor

I am not familiar with this product, but does this product not have
LDAP support? Can you not just tie it into LDAP and they can use their
OD/AD accounts? Then Kerberos for authentication?

bentoms
Release Candidate Programs Tester

Nope :(

Is a disk encrytion program called sophos safeguard.. No user plugin except what you see below… (my doing…)

I think I've sorted the text manipulation & am now getting:

GreyUK
btoms
Account btoms is a Network Account...
No SafeGuard account for btoms...
No SafeGuard account for btoms...

This is with:
if [[ "$loggedInUser" = "${SafeGuardUsers[*]}" ]]; then
echo "SafeGuard account already exists for $loggedInUser..."
break
else
echo "No SafeGuard account for $loggedInUser..."
Fi

Or

if [[ "$loggedInUser" == "${SafeGuardUsers[*]}" ]]; then
echo "SafeGuard account already exists for $loggedInUser..."
break
else
echo "No SafeGuard account for $loggedInUser..."
Fi

Any better way to check a variable against an array?

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

jarednichols
Honored Contributor

Here's a script we use to populate Firefox's sqlite database to whitelist 3rd party cookies. (It's also attached.)

The "sites.txt" and "remove.txt" ("Setup our arrays" section)are two plain text files with one entry per line. The ensures that the return at the end of the line is treated as a delimiter and thus the next line becomes a new array entry.

Everything up to the "Removal of sites" section is the setup to do the work – clear arrays, find information we need (logged in user for instance), populate the arrays (2 of them – removeSites and addSites)

The work of traversing the arrays and doing work is done in the "Removal of sites" and "Add sites that are in the addSites array" sections. Basically, the outer loop starts at the beginning of one array, the inner loop cycles totally through the other array. Outer array increments, runs through the inner array again.

j

#!/bin/sh

### Clear our arrays - good housekeeping just in case
unset removeSites
unset addSites

### Setup our arrays
addSites=( `cat /Library/Application Support/MITLL/cookies/sites.txt | tr ' ' ' '`)
removeSites=( `cat /Library/Application Support/MITLL/cookies/remove.txt | tr ' ' ' '`)

### Get logged in user
user=ls -la /dev/console | cut -d " " -f 4

### Change to our working directory
cd /Users/$user/Library/Application Support/Firefox

### Ensure the array properly handle spaces in file paths
IFS=$' '
### Get list of the user's profile paths and insert into an array
Path=(cat /Users/$user/Library/Application Support/Firefox/Profiles.ini | grep Path= | cut -d = -f 2)
### Reset IFS to default
IFS

### Removal of sites
echo "Removing third party cookie sites..."
for (( i = 0 ; i < ${#Path[@]} ; i++ ))
do
cd ${Path*}
printf "Working on " ; pwd
for (( j = 0 ; j < ${#removeSites[@]} ; j++ ))
do
echo "Removing:" ${removeSites[$j]}
/usr/bin/sqlite3 permissions.sqlite "delete from moz_hosts where host like '${removeSites[$j]}';"
done
echo
for (( k = 0 ; k < ${#addSites[@]} ; k++ ))
do
echo "Removing:" ${addSites[$k]}
/usr/bin/sqlite3 permissions.sqlite "delete from moz_hosts where host like '${addSites[$k]}';"
done
echo
cd ../..
done

### Add sites that are in the addSites array
Echo "Adding third party cookie sites..."

for (( i = 0 ; i < ${#Path[@]} ; i++ ))
do
cd ${Path*}
pwd
for (( j = 0 ; j < ${#addSites[@]} ; j++ ))
do
echo "Adding:" ${addSites[$j]}
/usr/bin/sqlite3 permissions.sqlite "insert into moz_hosts (host,type,permission) values ('${addSites[$j]}','cookie',1);"
done
cd ../..
done

--
Jared F. Nichols
Desktop Engineer, Client Services
Information Services Department
MIT Lincoln Laboratory
244 Wood Street
Lexington, Massachusetts 02420
781.981.5436

tlarkin
Honored Contributor

Oh my god....I am just being daft today....The answer is IFS, internal
field separator. That is how you have a bash script handle white spaces
and delimiting. I went to a concert last night so yeah, that is my
excuse....

bentoms
Release Candidate Programs Tester

Thanks guys. As always.

I'll have a bash later. Ha ha ha ha...
Regards,

Ben Toms

jarednichols
Honored Contributor

All hail me.

:)

--
Jared F. Nichols
Desktop Engineer, Client Services
Information Services Department
MIT Lincoln Laboratory
244 Wood Street
Lexington, Massachusetts 02420
781.981.5436

bentoms
Release Candidate Programs Tester

It's not you it's me…. I think… I've stripped out what I'm trying to do in a script you all should be able to test..

Basically, I need to check to see if the variable folderName is in the array FolderList..

Script below should tell me the that the Volume folder exists.. Any ideas?

#!/bin/sh

folderName="Volumes"

IFS=$' '
#List all SafeGuard users
FolderList=ls /

unset IFS

echo "$FolderList"

for i in "${FolderList[@]}"
do
if [[ "$FolderName" == "$i" ]]; then
echo "Folder exists..."
break
else
echo "Folder does not exist.."
fi
done

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

bentoms
Release Candidate Programs Tester

Got it working but in a weird way.. Via applescript (!)

set FolderList to (do shell script "ls /")

set folderName to "test"

tell application "Finder"

if FolderList contains folderName then

display dialog "here"

else

display dialog "not here"

end if

end tell

^^ this works..

So now my script is a bash script.. That calls an applescript.. That goes back to bash then if needed goes back to applescript ending in a bash script!

Regards,
Ben Toms
IT Support Analyst GREY Group
The Johnson Building, 77 Hatton Garden, London, EC1N 8JS
T: +44 (0) 20-3037-3819 |
Main: +44 (0) 20 3037 3000 | IT Helpdesk: +44 (0) 20 3037 3883

tlarkin
Honored Contributor

Well another option may be to run it through iHook. I have been
meaning to sit down and really tackle iHook but I haven't had time. It
allows you to run all sorts of scripts, grab user interaction, exchange
input/output between different languages and so forth. You can even
customize the GUI options in iHook as well. Though glad you got it
working

bentoms
Release Candidate Programs Tester

True. We've been looking at it for us.

But no additional software was one of the remits for this & it's being used in environments I'll not have access too.

Politics eh?

Regards,

Ben Toms

wmateo
Contributor

@bentoms did you ever get this working? Currently we activate Sophos Manually by dragging the ZIP file to the sophos preferences. I want to get a way to completely automate it when we hand the laptop to the user - will there be any interaction at all?

sean
Valued Contributor

If 'SafeGuardUsers' returns a list of users like:

Btoms
GreyUK

Then

if [[ "$loggedInUser" == "${SafeGuardUsers[*]}" ]]

is never going to be true. This is saying, does a single string equal a list of strings. You can loop through an array and run tests, but bash has a built in which will do this for you.

Check out the following:

#!/bin/bash

loggedInUser=`stat -f%Su /dev/console`

UserList=`ls -1 /Users/`

function FindUser
{
        # Equating numbers, so single brackets fine 
       while [ $# -gt 0 ]
        do
                # Equating strings, so double bracket and double equals and quote to be safe from spaces
                if [[ "$1" == "$loggedInUser" ]]
                then
                        echo "Found: $1"
                else
                        echo "Not found: $1"
                fi
                shift
        done
}

FindUser $UserList

exit 0

acdesigntech
Contributor II

I usually handle this by looping through the array(s) and doing a comparison on each item. Might be a little more CPU intensive.... but it works nicely for my purposes.

Looping through a pre-populated array:

#!/bin/sh
## Make an array for all potential user pref files we need to delete:       
UserFiles=( 'Library/Preferences/com.microsoft.autoupdate.fba.debuglogging.plist' 'Library/Preferences/com.microsoft.autoupdate.plist' 'Library/Preferences/com.microsoft.autoupdate2.debuglogging.plist' 'Library/Preferences/com.microsoft.autoupdate2.plist' 'Library/Preferences/com.microsoft.autoupdate2.plist.lockfile' 'Library/Preferences/com.microsoft.communicator.plist' 'Library/Preferences/com.microsoft.communicator.plist.lockfile' 'Library/Preferences/com.microsoft.entourage.database_daemon.plist' 'Library/Preferences/com.microsoft.entourage.database_daemon.plist.lockfile' 'Library/Preferences/com.microsoft.entourage.database_utility.plist' 'Library/Preferences/com.microsoft.entourage.office_reminders.plist' 'Library/Preferences/com.microsoft.entourage.office_reminders.plist.lockfile' 'Library/Preferences/com.microsoft.Entourage.plist' 'Library/Preferences/com.microsoft.Entourage.plist.lockfile' 'Library/Preferences/com.microsoft.entourage.syncservices.plist' 'Library/Preferences/com.microsoft.entourage.syncservices.plist.lockfile' 'Library/Preferences/com.microsoft.error_reporting.debuglogging.plist' 'Library/Preferences/com.microsoft.error_reporting.plist' 'Library/Preferences/com.microsoft.error_reporting.plist.lockfile' 'Library/Preferences/com.microsoft.Excel.plist' 'Library/Preferences/com.microsoft.Excel.plist.lockfile' 'Library/Preferences/com.microsoft.helpviewer.debuglogging.plist' 'Library/Preferences/com.microsoft.helpviewer.plist' 'Library/Preferences/com.microsoft.myday.plist' 'Library/Preferences/com.microsoft.myday.plist.lockfile' 'Library/Preferences/com.microsoft.office.plist' 'Library/Preferences/com.microsoft.office.plist.lockfile' 'Library/Preferences/com.microsoft.office.setupassistant.plist' 'Library/Preferences/com.microsoft.OfficeConverter.plist' 'Library/Preferences/com.microsoft.OfficeNotifications.plist' 'Library/Preferences/com.microsoft.OfficeNotifications.plist.lockfile' 'Library/Preferences/com.microsoft.openxml.excel.app.plist' 'Library/Preferences/com.microsoft.outlook.database_daemon.plist' 'Library/Preferences/com.microsoft.outlook.office_reminders.plist' 'Library/Preferences/com.microsoft.Outlook.plist' 'Library/Preferences/com.microsoft.Powerpoint.plist' 'Library/Preferences/com.microsoft.setupassistant.plist' 'Library/Preferences/com.microsoft.setupassistant.plist.lockfile' 'Library/Preferences/com.microsoft.visual_basic.plist' 'Library/Preferences/com.microsoft.Word.plist' 'Library/Preferences/com.microsoft.Word.plist.lockfile' 'Library/Preferences/com.microsoft.Entourage.plist' 'Library/Application Support/Microsoft/Office' 'Library/Preferences/Microsoft' )
#------------
echo "Now removing user preferences"
for USER_HOME in /Users/*;
do
    USER_ID=`basename "${USER_HOME}"`
    if [ "$USER_ID" != "Shared" ]; then
        echo "Now removing $USER_ID preferences..."
        echo "---------------"
        for (( i = 0; i < ${#UserFiles[@]} ; i++ ))
        do
            myFile="${USER_HOME}/${UserFiles[$i]}"
            if [ -e "$myFile" ]; then
                if [ -f "$myFile" ]; then
                    ### file object is a file so rm it ###
                    rm "$myFile" > /dev/null 2>&1
                else
                    ### file object is a directory, so rm -r it ###
                    rm -r "$myFile" > /dev/null 2>&1
                fi
            fi
        done
    fi
done

Excerpted from my MS Office uninstall script