The macosxhints Forums

The macosxhints Forums (http://hintsforums.macworld.com/index.php)
-   UNIX - General (http://hintsforums.macworld.com/forumdisplay.php?f=16)
-   -   Script to delete user specific folders (http://hintsforums.macworld.com/showthread.php?t=85991)

tlarkin 02-15-2008 11:38 AM

Script to delete user specific folders
 
So, I have a policy created that will delete certain folders in a users home directory to delete certain preferences so when an update of the application is pushed out it gets a fresh load of preferences. As of now the script works and it is written to delete the local hidden admin account and the current user that is logged in.

One small problem, in small cases there are perhaps a few user accounts on the machine. All user accounts are mobile so they are both network and local and i need to script so that it pulls up every user account that is in /Users and wipes out these specific folders.

So, how do I code a script to grep or pull up all user accounts and then delete certain user folders? These are tiger clients too, so could or should I use the netinfo database from the command line?

Thoughts and suggestions?

Thanks in advance

hayne 02-15-2008 11:47 AM

I don't understand the problem.
Why isn't it as simple as looping through (or wildcarding through) all folders under /Users ?

tlarkin 02-15-2008 12:05 PM

Um, I am not sure how to properly code it to loop through all the users in the /users directory I guess is the problem hayne.

Mikey-San 02-15-2008 01:45 PM

This should do the trick. Uncomment line 73 (the rm line) when you're ready to test it out.

Errors the script encounters are logged to the system log via /usr/bin/logger.

Code:

#!/bin/sh

PATH='/bin:/usr/bin'
ls=/bin/ls
rm=/bin/rm
logger=/usr/bin/logger


#############################################################
# Set the internal field separator to the newline character.
# This lets us iterate through each line of a file or
# \n-terminated stdout data. Think of this as a text item
# delimiter.
#############################################################
IFS=$'\n'


# success
noErr=0

# there was an error encountered while removing a directory
errCouldNotRemoveDirectory=1


# folders whose names match the items in the exemptedFolders array will not be deleted.
# add the name of a folder here to exempt it from this script's actions.
declare -a exemptedFolders
exemptedFolders=( "Shared" )

# test to see if an array contains an item. takes two parameters. the first is an array of
# items to search, the second is an item for which to search.
# example usage:
# arrayContainsItem $anArray "$someString"
function arrayContainsItem()
{
        result=1

        array=$1
        item=$2
               
        for each in ${array[*]}
        do
                if [ "$item" == "$each" ]
                then
                        result=0
                        break
                fi
        done
       
        return $result
}


# get a listing of everything inside /Users
usersDirectoryContents=`$ls /Users`

# iterate over all of the items in /Users
for dir in $usersDirectoryContents
do
        arrayContainsItem $exemptedFolders "$dir"
        exists=$?

        # if this item isn't one of our exempted folders, we want to remove it.
        if [ $exists != 0 ]
        then
                target="/Users/$dir"
               
                # make sure it's a directory; we only want to remove directories.
                if [ -d "$target" ]
                then
                        # attempt to remove the directory.
                        echo "Removing: $target"
                        #$rm -rf "$target"
                        rmResult=$?
                       
                        # if rm didn't exit with 0 status, something went wrong. log it and bail!
                        if [ rmResult != 0 ]
                        then
                                $logger "Error $errCouldNotRemoveDirectory: $target could not be removed. $rm exited with status $rmResult. Bailing."
                                exit $errCouldNotRemoveDirectory
                        fi
                fi
        fi
done

exit $noErr


tlarkin 02-15-2008 01:48 PM

thanks mikey I will try it out, and you didn't have to do that I would have researched it myself. I appreciate it.

Thanks

Mikey-San 02-15-2008 02:01 PM

No prob. Hopefully, the comments made sense.

Let us know if it works for you or not.

ghostdog74 02-17-2008 01:22 AM

that's one good script. However if i get the requirement correct, its just equivalent to something like
Code:

find . -type d ! -name "Shared -exec rm {} \;
except it only exclude one directory.

Mikey-San 02-17-2008 01:28 AM

Yeah, I was just gonna one-liner it, but wanted to give tlarkin more logging opportunities (since he can pepper them anywhere he likes later) and an ability to exempt more directories in the future. It's the "completist sysadmin" response taking over, probably.

tlarkin 02-19-2008 09:56 AM

So I was reading through this script, and correct me if I am wrong but if I need to delete these two folders:

~/Library/Application\ Support/Firefox

~/Library/Preferences


in your script I just need to add them to the target value, correct?

This is because if I don't delete these two folders and push out our new firefox package it picks up all the old user preferences in the new vesrion which are no longer correct. Our network changed and since firefox has its own settings I need to push out a new copy of firefox. Which I have done, and I have written a script that deletes those directories. The only problem is the policy is set to run once per a machine, so if someone logs into someone else's laptop and it runs the script will only run on that user, due to my lack of programming knowledge. I could set the policy to run as once per a user, but that would then install firefox many different times on the same machine, which would be a waste, and I could set the scripts as once per a user in the policy but then I have the script running at different times of the software being deployed, and that sounds sloppy.

Mikey-San 02-19-2008 01:25 PM

The script I posted, as well as the one-liner, delete every folder in /Users except /Users/Shared. Everything. All user folders get rm'ed from the top, which includes their contents. That's what you wanted, right?

tlarkin 02-19-2008 01:34 PM

Quote:

Originally Posted by Mikey-San (Post 452504)
The script I posted, as well as the one-liner, delete every folder in /Users except /Users/Shared. Everything. All user folders get rm'ed from the top, which includes their contents. That's what you wanted, right?

heh, nope I need to remove specific holders to a home directory, mainly in ~/Library/Preferences and in ~/Library/Application Support.

I was reading through your script and saw that, and I am sorry that i didn't clarify, I just need to delete a few specific folders.

Sorry for the confusion.

Mikey-San 02-19-2008 02:03 PM

S'ok. Writing a script to delete just a couple of folders whose specific path you know is pretty straightforward. How are you running them? A login hook?

tlarkin 02-19-2008 03:02 PM

Quote:

Originally Posted by Mikey-San (Post 452516)
S'ok. Writing a script to delete just a couple of folders whose specific path you know is pretty straightforward. How are you running them? A login hook?

Sort of. I am running casper suite at work (which is a nifty product) that has a binary client running via SSH to a casper server which houses network policies I create. The client checks in with the server every 15 minutes or when it can, and checks for current jobs that are queued in its group. it then does a forced pull (not a push from the server there is a difference) from the nearest file share (also configured on the network side) of that policy.

It can be triggered at log in/out, boot, every 15 minutes, or by any of the above.

Then each policy has the options of installing packages, running scripts, updating inventory, reseting passwords, so on and so forth. It's pretty dope actually, and yes I just said dope.

Like for example, I have to push out CS 3 to like 200 laptops with mobile users that run around all over the place. I am not going to push out CS3 over the wireless, that is just retarded, so instead I had my Cisco guy set up a managed 48 port high speed switch to a specific VLAN. Only this certain switch has this VLAN in my whole subnet which I am in charge of. So, I then create a policy to install CS 3 to this specific VLAN, and only to these specific groups. I then have the user come to me, I jack their laptop into the switch and reboot. Upon reboot CS3 automatically installs. It's dope. I don't have to do a thing after that. With the minor problem of how Adobe does some funky things on first run, it hashes hardware information about the system. So, you must run the CS3 app twice the first time. When you run it once it asks for license key, well that is embedded in the install, so it hashes all the info the firs time you run it. Quit the app and re-run it and it will have that hashed info and never ask for a license key again. We of course a site license. I also have an inventory of how many installs I have done, which is right around 150 right now so i am well below my limit of what a site license is.

It also does everything via ssh, so its secure.

My problem is, that I am sort of a scripting newbie. I know bash very well, but when it comes to writing variables and loops, and things like that I don't quite fully grasp all of it just yet. I mean I read your script and realized it deleted everything except the exempt folders, but I wouldn't be able to write that script you wrote from scratch - if that makes sense.

Mikey-San 02-19-2008 03:19 PM

For your task, if you just want to target a couple of specific folders, you probably don't need anything fancy. Couple more questions:

1. Under what user privilege will the script run?

2. You've got a few ways to trigger it (log in, every X minutes, etc), so you can go a couple of different routes here. Examples:

A. When User A logs in, the script is triggered and it deletes the specified folders in User A's home dir.

B. Every X minutes/hours/whatever, the script is triggered and it deletes the specified folders for all users.

C. At boot, the script is triggered and it deletes the specified folders for all users.

Which do you think you want to do? (I would think at boot or log in, yeah?)

tlarkin 02-19-2008 03:28 PM

Quote:

Originally Posted by Mikey-San (Post 452537)
1. Under what user privilege will the script run?

Root

Quote:

2. You've got a few ways to trigger it (log in, every X minutes, etc), so you can go a couple of different routes here. Examples:

- When User A logs in, the script is triggered and it deletes the specified folders in User A's home dir.

or

- On boot or every X minutes/hours/whatever, the script is triggered and it deletes the specified folders for all users.

Which do you think you want to do?

This is not totally relevant to the scripting process I would think. Since I can set all of that via the policy scope, and I can change it via the casper client. For this particular need I would do it, once per a machine as the frequency, so once a single computer has the script ran on it, it will mark it as done and won't run it again, and then have it delete these preferences out of every local home directory on the laptop. We do home synchronization here, so their home is sync'd over the network. That way they can authenticate locally to the machine if outside our network.

All my options though are adjustable via the web front end of the casper server. like I said it is a really nifty product. Which is why my scripting skills are kind of weak. since I can do most things with the client, and the client uses the under the hood unix, I really haven't been challenged enough to learn some heavy scripting. If you know of any crash course scripting websites I would be more than happy to look through them. I have a desire to learn this stuff. All of my scripts have been like maybe 5 lines at the most, which includes your line of explaining what the script does.

**EDIT oh yeah thanks again for helping, I'd email you a beer if that was possible!

Mikey-San 02-19-2008 04:35 PM

The scripting process would be affected if you were doing it every time at login, since you could do something super-simple that just deletes the specified folders in the home dir of the user who just logged in. But if you want to nuke 'em for all users at once, we'll go a similar route to what I did above. So, lemme make sure I got it straight:

1. The script runs with superuser privileges.

2. The script will be invoked by you, the sysadmin, at will, but you can also set it to run periodically automatically.

3. The script will remove the target directories from all home folders, at once, on the client machine.

Do I have it right?

Mikey-San 02-19-2008 04:45 PM

As for learning, I recommend:

http://tldp.org/LDP/abs/html/

It's very straightforward, builds steadily, and doesn't overload you. (There's an example in the intro that is complicated, but it's just a demonstration of complexity, not something it expects you to understand at first. When you're done with the book, you'll grasp the example.)

There are a couple of O'Reilly books on Unix/bash scripting, but I don't know much about them, so I wouldn't be able to make a recommendation.

tlarkin 02-19-2008 04:53 PM

Correct.

Since users that I support often at times trade laptops, or one user will borrow another user's laptop to quickly check email or what not, sometimes their are multiple users synchronized with their network home on a single laptop. Now, if I run the scope at once per a user I run the risk of the user not being the actual owner of the machine. But, if I do it at a scope of once per a machine, then I can hit all the users in /users and just be done with it, also they will receive the new package at the same time and be marked in inventory as being updated.

So yes your assumptions are correct

1. yes, it runs as a local admin account on the system. There is a specific local hidden admin account that is used for the ssh session that the casper client/server have. So, all scripts will be executed as if the local admin were running them, so sudo may be needed.

2. Correct again, I will most likely set the policy to run once per a machine and be triggered by any, which includes log in/out, reboot, or every 15 minutes.

3. It will remove specific user data that is stored in each users home, mainly preferences. This is because when I push out a new software application package and it requires new settings because we changed something I need to delete the old user preferences. Otherwise, it will install and use all the old user preferences and thus won't work properly.

Thanks for the link, I book marked it and am reading through it now. Got text wrangler up and running and am going to start creating scripts I think I may need in the future and go from there.

Thanks a ton!

Hal Itosis 02-19-2008 07:12 PM

Quote:

Originally Posted by tlarkin (Post 452564)
3. It will remove specific user data that is stored in each users home, mainly preferences. This is because when I push out a new software application package and it requires new settings because we changed something I need to delete the old user preferences. Otherwise, it will install and use all the old user preferences and thus won't work properly.

As far as this part goes, I think hayne's wildcarding suggestion will work well.
You can test it with something like:

ls -ld /Users/*/Library/{Application\ Support/MyAppFolder,Preferences/MyAppFolder}

Only... sudo isn't enough for the wildcard pattern-matching to work (from a Terminal)... unless,
you put those lines in a script, and then call the entire script with sudo. [or simply run from a
root shell... so sudo wouldn't be necessary.]

The reason something like sudo ls -ld /Users/*/Library/Application\ Support doesn't work in Terminal
is that our shell does the '*' expansion before passing it to sudo... so not all matches get to happen.

Contrast that with:
$ sudo bash
# ls -ld /Users/*/Library/Application\ Support

Then it works!

...or put the lines in a script, and do sudo myscript

[there's a thread around here somewhere in which hayne struggled to teach me that principle. ;)]

-HI- <sometimes i'm not easy>

hayne 02-19-2008 07:38 PM

Quote:

Originally Posted by Hal Itosis (Post 452590)
The reason something like sudo ls -ld /Users/*/Library/Application\ Support doesn't work in Terminal
is that our shell does the '*' expansion before passing it to sudo... so not all matches get to happen.


True enough in general- but in this particular case, the /Users folder is readable and searchable by all, so the expansion of the * under your current (non-root) user account should suffice to give the desired result.

[edit]
My comment in this post is incorrect - see discussion in posts #24 and #25 below
[/edit]

Mikey-San 02-19-2008 08:33 PM

I'd probably go with the wildcard one-liner if you don't need any special exclusion or logging. Since you're actually sitting at the unit when you do this--which I now know--logging probably isn't going to gain you anything with something this simple. If you need to wrap it in a shell script for Casper to use it, this is really all you need:

Code:

#!/bin/sh

PATH='/bin:/usr/bin'
rm=/bin/rm

$rm -rf '/Users/'*'/Library/Application Support/Firefox'
rmFFResult=$?

$rm -rf '/Users/'*'/Library/Preferences'
rmPrefsResult=$?

if [ $rmFFResult != 0 ] || [ $rmPrefsResult != 0 ]
then
        exit 1
fi

exit 0

I broke the two targets into separate lines purely for readability. This is equivalent to what Hal posted, but wrapped in a script in case you need it.

Mikey-San 02-19-2008 08:42 PM

And as a side note, when the targets exist in none of the folders matched by the wildcard, either in the one-liner or the wrapped version, rm will spit out a "No such file or directory" error and exit 1. You can do what you want with this, suppress it if you like, whatever.

tlarkin 02-19-2008 09:22 PM

Hey thanks guys. The end users never see this stuff run, its all via ssh in the background under the hood. They only thing they see is a dialog box that says you need to restart your computer it has been updated, click OK to restart and save all current data, blah blah blah

Casper has its own binary as well, which I can use (and I am still learning) and it will use the under the hood unix in OS X to accomplish a task.

For example, we have as of right now 8 or so different images, and each image is the same except for passwords, which are subnet specific. So, I knew that having 8 versions of the same image may have been the working solution before i was hired on and there were other higher priority things to get done so it got put on the back burner. Well, I just updated the image, and reset all the passwords to some basic generic ones in the image, then wrote a casper script using casper's binary to set the specific passwords for the admin accounts and for the firmware. Now, these scripts are in plain text and sit on AFP shares on OS X servers. The owner and the only user that can access these files is the hidden local admin account for casper, which is not the same local admin account for local administration. Then that information gets pulled from the server via ssh, encrypted and all from a very secure AFP share to the client machine and the passwords are automatically set. This is really awesome. I can even set up a policy so if you change subnets, your passwords change too for the administration side. That way, depending on which subnet you are on depends on which admin you see for help since we are split up into different buildings and each one is on its own subnet. That way each admin doesn't have to remember 8 sets of unique passwords for the local admin and the firmware, while only I know the casper account password. That is the most secure way I have come up with to deploy passwords and house 1 generic image for 5,000 laptops over 6 different subnets. Only achievable by casper (I know shameless plug - you almost think I am working for them). This also creates a very simplistic netboot - reimage process. You reimage several macbooks at once via netboot and part of the post script image policy is that it will push out those password settings, so the IT person doesn't have to touch it. You can also let fewer people know the passwords since fewer people will need to touch it since you are already more efficient.

I need to start a blog of what I am doing, some really cool stuff I am doing and able to do now with our infrastructure and if it were maybe documented better I think Apple could get that kick over into the enterprise environment and then maybe Jobs will finally say, they are in fact an enterprise company.

Hal Itosis 02-20-2008 12:20 AM

Quote:

Originally Posted by hayne (Post 452595)
True enough in general- but in this particular case, the /Users folder is readable and searchable by all, so the expansion of the * under your current (non-root) user account should suffice to give the desired result.

I tried before I posted.
How about you? ;)

sudo ls -ld /Users/*/Library/Application\ Support

-it can't "expand" below each user's ~/Library.
-it needs to see full paths, not just usernames.

hayne 02-20-2008 12:29 AM

Quote:

Originally Posted by Hal Itosis (Post 452656)
I tried before I posted.
How about you? ;)

sudo ls -ld /Users/*/Library/Application\ Support

Oops - sorry. You are quite right. I responded too quickly without thinking about what command you had given.
What I said about the /Users folder being world-accessible was correct but I didn't think about the sub-folders that followed the *. The Library sub-folder in each user's home is not readable unless you are 'root'.
So, you are quite right that the wildcarding won't work in that case.

Mikey-San 02-20-2008 12:46 AM

It will work if it's part of a shell script, though, whether via sudo or actually running from a root shell. (I tested the script above with ls instead of rm and it worked just fine.)


All times are GMT -5. The time now is 05:42 PM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2014, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.