In the previous exercises you been writing scripts to do things like add users Well now it's time to
do the opposite.
We're going to write a script that deletes users and actually this particular Scrubb not only deletes
users that can disable them and it can archive a user's home directory.
So the first thing of course we need to do is come up with a little requirements document if you will
and figure out what in the world do we want our script to do.
And here are the things that we want the script to do and how we want it to operate and what we want
to look like.
Well the first thing we decided on was that we want to make sure that this script is called disable
dash local dash user dot sh.
Since we're doing some system administration type stuff like deleting users or disabling them we need
to make sure that whoever is executing this script as root privileges or super user privileges.
So we're going to put a check for that in the top of our script.
We also want to provide a usage statement much like you would find in a man page if the user that's
executing the script does not supply an account name on the command line.
And then of course we're going to follow good Linux programming conventions and exit our script with
a non-zero exit status.
We also decided to use disable as the default action for this script and we also decided that we can
let the users decide if they want to do something more destructive such as delete an account or remove
the user's home directory.
So we've given them a few different options again the dash D will delete an account instead of disabling
it.
Nash are you going to remove the home directory and a dash a will create an archive of the home directory
associated with the account and then store it in the forward slash archive directory.
Now by the way this is just kind of an arbitrary decision that I made.
I'm going to put these things in forward slash archives.
There is no standard for such a directory.
This is not going to be a directory that you're going to find by default on a newly installed Linux
system.
It's not part of the Linux file system hierarchy.
It's just a folder that I decided to use.
In that respect what we need to do is just make sure that that directory exists and if it doesn't exist
we're going to have our script created.
Now if a user does something interesting like supply an option that we don't account for then we're
going to give them that usage statement and exit as well.
We also decided to make it a little bit easier on the end users that are going to be running this script.
They can supply you know one user to users or however many users they want at the command line so if
they want to delete seven users well they can supply all seven users at once on the same command line.
And this script will simply loop through them all and perform the exact same action against all those
users.
So if a user supplies the desde option and seven accounts Well it's going to delete all seven of those
accounts.
Speaking of deleting accounts we don't want someone to do something interesting like delete the root
account and make our system unusable.
Along this logic we don't want to let people who are not system administrators do things like disable
any system account.
We know that typically system accounts have a user id less than 1000.
So let's just put a little check for that in our script and we'll exit saying hey we're not going to
do that.
If a system account needs to be deleted we'll give that task over to a system administrator and let
them do it.
If we encounter an error along the way either deleting or disabling or archiving the account or creating
a directory or what have you we're going to tell the user that we encountered a problem and then exit
the script.
Also the last thing we want to do is just make sure that we display the user name and any actions that
we took against that account or username for the user that executed the script.
So that pretty much does it for our requirements.
Now let's get to scripting here I have a terminal open on my local system and I'm going to go into the
shell class folder.
We're still working on a local user's project and I'm going to bring up the virtual machine and log
into it.
Now we'll go into our shared folder of forward slash vagrant.
And again we decided to name this script disable local user.
SH
It goes without saying we're going to supply a shebang line and then we'll just give a comment about
what the script is going to do.
So we know that we're going to be executing some commands that require root privileges so let's just
go ahead and check that right away.
So if the user ID is not equal to zero then they are not root.
This is an error message we're going to send this to standard error.
And then we're going to exit with a non zero exit status.
We also want to parse the command line options so we'll do that next.
We know that we can use get ups in a while loop.
We'll specify our upstream.
Here are the options that we're going to accept and we're going to accept to delete or to remove Ada
archive and we'll use the variable option.
We'll check that option in the case statement here.
So if someone supplies D.
Let's set a variable called Delete user and we'll just set that true.
And then later on in our script we'll check to see if the lead user is true and if it is then well we'll
delete the user
here I'm going to do something slightly different.
If you recall the user del command allows you to specify a dash r option which removes the user's home
directory.
So what we're going to do here is use this remove option variable in the user dels statement.
When we get to that in this script.
So if this is set to nothing or if the option is never supply this dash our option then remove underscore
option is going to evaluate to an empty string and nothing will be substituted in its place.
And so then user data will be executed without this dash our option.
Now on the other hand if someone does specify Dasch are then the user will be deleted with Dash.
Now it's going to make total sense when you see it the minute I just want to talk about that for just
a second.
We'll do something similar here that we did the delete user option which is if someone gives us a dash
we'll just check for this archive being true later in the script.
And if they give us any other option then we're going to tell them how to use our script and exit.
Now my key statement here is looking pretty nice and compact.
And I think I'm going to use a function for displaying this usage statement and then exiting the script.
Now another argument for creating a function like this is that we're going to have to do this same thing
multiple times in the script because we're going to have some other checks and then we're going to give
them a usage statement and exit.
So let's go back to the top of our script here and go ahead and create our function
as you remember dollar signs zero is always the name of the script not the name of the function like
you may into it.
That's not what happens with dollar signs zero it's always the name of the script.
So we can safely use that in the function.
So now we have some optional options so those options that are optional go in brackets.
Then we have a mandatory argument.
So we're not going to put that in brackets but obviously we have additional users that we can allow
them to specify and they can specify multiple ones so we'll do this we'll use an ellipsis there.
Now we're going to exit and that will wrap up our usage function.
OK let's jump to the bottom of our script.
And now after we process our options let's shift all those options al the way.
And then anything that's left over are going to be user accounts and then later we'll loop through those
user accounts.
So we want to make sure that the user gives us at least one account to operate against if they don't
then that means they don't know what they're doing.
So we're going to give him some help.
Call our function that we wrote and close our IF statement.
Now we're ready to loop through all the usernames that were supplied as arguments.
I like to tell whoever is executing the script what user we're processing or working on.
Again they may supply multiple users on the command line.
We want to make sure that we're not removing any system account so we want to get the ID of the user
that we're processing the Dashiell returned the id the number for a username
and then we can test against that.
So if the idea is less than 1000 then we're not going to remove that account.
Before we do anything like delete a home directory let's make sure we create an archive of it.
If the user requests us to do that.
So if someone passed in the dash option then archive gets set to True and if archive is true.
Well then let's make an archive.
Actually I'm going to create a variable called archive underscore R which represents the archive directory
and I'm going to use this multiple times in the script.
So I think what I'm going to do is put it at the very top of the script even before our first function
here of usage.
And really what this is acting as is a constant variable.
You can even do this you can even make it read only if you like.
So I'm going put it at the top because this is the only thing that I can think of that we might want
to adjust later on down the road.
For example if we want to put these archives on another place in the file system then we can just change
this variable at the very top of our script make that one small change and not change anything else
and be good to go.
OK let's jump back to the bottom and continue scripting.
So what this statement says is if not exist directory archive directory then.
OK so how did I get that exclamation point.
Well you know that the things in double brackets here are tests and you know that we can get information
on the test.
We can run by using help test at the command line and if we look at that actually I'll just do that
now.
Hope test and it gives us a list of tests and you can see here that exclamation mark expression means
true if the expression is false so you can think of that as negating the expression or you can think
of the exclamation point as not.
So that's where I got that.
So ultimately what you're saying is if the archive directory doesn't exist.
Well guess what we need to create it.
By the way I'm using the dash p option to the make or command because if we have a archived directory
that has multiple subdirectories for example we can do something like archive users or or whatever.
And if the first directory the parent directory or parent directories don't exist then we need to create
them and that's what that Dasch option does to make a command it creates parents if you will.
So in our particular case we're just using for its slice archive so it doesn't matter.
But if we were to change that variable at the beginning of our script to something that does include
subdirectories then we'll need to use a dash piece or kind of future proofing our script if you will
here.
So if the make command fails then that's going to mean that we can't put any of the archives you create
in a directory because a directory didn't exist or wasn't able to be created.
So we're going to bail on our script here so let's do another check.
So we'll check the return status of make our
if it's anything but zero we have a problem.
So now that we know the archive directory exists let's go ahead and archive the user's home directory
and move it into that directory.
Now by default normal user accounts have home directories that live in Fort slash home.
So if we have adjacent account then my homework is going to be for it slash home for Jason.
Now if you have an application account or system account that's probably going to live somewhere else
in the file system.
For example the route home directory is forward slash R O T an application directory might be for exe
VAR for s w w w for a web user or something like that.
So here we're also using this convention to be another safeguard if an account doesn't have a home directory
and for its last home then it's probably a system or an application account.
And at that point we probably want a system administrator to look at it manually do it or whatever instead
of just whoever happens to be managing accounts now those people I'm sure are knowledgeable about managing
accounts.
They just may not work on Unix and Linux systems all day like we do.
So again we're just going to reserve that for a higher level of person that's not using this script.
On the other hand we could have made the decision that we're just going to extract the proper home directory
and delete it no matter where it is on disk or create an archive of it no matter where it lives on disk
so they can leave that up to you.
But here I'm just going to do it this way.
So we're going to create an archive file and we're just going to give it a full path here.
We're going to put it in the archive directory and then we're going to name it user name and we're going
to make it a compressed tar file so that's going to be t g z.
Easy for me to say.
And here we go.
Here's our check about the home directory.
So if the home directory does exist then that's a good sign we'll go ahead and move ahead and make our
archive.
We're going to compress that so there's a dash z option C to create an archive.
F is the location of the archive file.
Then the path to archive which is the home directory and Taar is going to make some noise so we're just
going to send that to dev null.
We don't want the user to see any output created by Taar just going to be distracting to them.
But we do want to make sure that Taar execute successfully
So if TAR exits with a non-zero exit status we'll say we couldn't create the archive and then exit with
a non-zero exit status ourselves.
And the way I just noticed a typing mistake I have a peer.
I'm used to doing closing bracket and a quotation mark but I don't need that there and if I remove it
then I see my syntax highlighting go back to normal here.
And so I notice that because this syntax highlighting look different.
That's what QBE and to that there.
So that's kind of good to have an editor with syntax highlighting
K so this if statement says hey if there is a home directory.
Daschle if this thing called home Durer is a directory and exists then you archive it.
And if that doesn't exist or it's not a directory then we're going to tell the user hey that doesn't
exist or it's not what you think it is we're going to get out of here.
Exit 1.
Now this concludes our if archive equals true if statement.
And now we want to see if we need to delete the user or not.
So let's do this
so here is what I was talking about earlier with this remove option.
So if we're going to delete a user we need to use the user del command.
Additionally if we want to delete the user's home directory We need the dash our option.
So if they give us a dash or option we store that and remove underscore option.
Now here remove underscore option will evaluate to dash or if they supply Dasch are or it will evaluate
to an empty string.
In that case it just going to be like user space space user name which is going to give us the exact
result that we want.
So that is one way to handle this kind of situation.
There are other ways but this is a pretty simple way to do this.
So we want to check the exit status of the user Dell command because we don't want the user thinking
that an account got deleted when it really didn't get deleted.
Now I want to point out something here we're doing a lot of the same thing here which is checking for
an exit status if it's not zero then we're going to give an error message an exit.
So I'm doing each one explicitly and changing the echo statement for each one so that the user knows
exactly what failed in the script.
In theory you could simplify this a bit and say Write a function that well executed command and then
check the return status on that command and then bail or exit your script.
If it doesn't succeed.
So there is some food for thought or maybe that some extra credit after you write the script this way
then maybe write a script and have it use a function called a run command or run in check or something
like that.
Just something to keep in mind
if we make it past the if statement that means the account was deleted and by the way here's another
thing you could have put this inside of the if statement like this you could have said if there was
a non-zero exit says we have a problem get out of here or if there was not not not zero.
If they exist that's one zero more or less than the account was deleted.
I'll leave that up to you.
I'm just going to do it this way if it makes it past that if statement then the account was deleted.
That makes sense in my mind.
So if the delete user is set to true we do all that above we use user Dell.
If it's not set to true then we're just going to disable the account or expire at I can do that with
a S.H. age command.
And again we're just going to actually duplicate this bit of code so I'm just going to copy it and paste
it and just change it.
Here it says the account user name was not disabled.
Again if you're copying and pasting that may be a sign you need a function
and go ahead and grab these two lines appear as well.
Again if we get past this if statement that means the account was disabled
that brings us to the end of that if statement.
That also brings us to the end of our For loop and that also brings us to the very end of our script.
We are going to exit with a zero exit status.
Now I know with long scripts like this I can make some mistakes.
And also one of the most common mistakes are typing mistakes not necessarily logic mistakes.
So I'm going to do is actually go back to the very beginning of this script and look for things like
quotation marks spelling mistakes brackets braces kind of some normal hot spots that I may have some
errors and some is going to jump back to the top and just kind of read things through and correct them
as I see them.
OK.
The first here I see the script we can call it this script that's a minor one and a comment not going
to make a difference to functionality but there's a little typing mistake.
Here's another one.
Here's another one I have a dollar sign in the wrong place.
We go inside the quotes there as you can see can you see the syntax highlighting change so that's good.
That's another area that I found here.
OK at least I found a couple and corrected them before I executed my script.
If not then I would have just started debugging then maybe the error message would have given me an
indication of where at.
In the script I had the air and so on.
I would have also perhaps gone to the very top here and you some options like Dash X Daschle or dash
VI or even all three combined there to do some debugging that way or even some manual debugging like
this.
I would just echo archived deicer and then exit for example to create a manual stop point or checkpoint
if you will.
So those are just a couple of debugging tips now that we have our script created before we execute it.
We need to give it executable permissions.
Now let's execute this script without super user privileges and see what happens.
Says Please run with seducers route.
That's what we want.
Let's make sure it exited with a non-zero exit status.
And sure enough we have an exit status of one.
So this time let's run it with the proper privileges but don't supply any options or don't supply any
usernames.
OK we get a usage statement just like we wanted.
And we also get a non-zero exit status which is exactly what we expect now that supply an invalid option.
Let's apply a dash Z which we don't do.
And it says disable local user illegal option dashes Z.
Now that is coming from the get shell built in.
But the usage statement of course is coming from our usage function.
Since we know that that function ends with exit one we can confirm that indeed our script exited with
a 1 exit status.
Now it's trying to disable a system account.
So on these particular systems we're not really using mail and no mail is a system account user with
a low I.D..
So let's go ahead and delete that.
Now if we the leader the mail account and probably nothing bad is going to happen.
And again these are test systems so we could throw them away and build a new one.
So let's try it here to disable local user and we'll try to disable the mail user.
It says I'm refusing to remove the mail account that has a huge ID of 8.
So that is exactly what we want.
Again a nonzero exit status to go with that.
So now what I'm going to do is actually create some test accounts here to test my script with an actually
wrote a script to create these test accounts.
I'll just show it to you really quick here.
It's a pretty simple script.
It just is mainly a for loop that sets everybody's password.
Yes.
One two three creates the count and then sets the password so I'll go ahead and add those test accounts
now.
And now we have a few accounts to play with.
Now let's run our script against one of these test users that we created.
Here it says the account was disabled.
So let's make sure it's disabled by trying to log into it.
We'll use our handy password of pass 2:59.
And it says your account has expired please contact your system administrator.
So that's the exact kind of behavior we want just to be thorough.
Let's also make sure that the home directory for that user still exists.
Sure enough it does.
No it still leaves the mark h account.
So we'll give our script here we need the dash D for the delete option and then the account of Mark
H.
It says processing user and the account was deleted.
Let's see if it was say no such user that means it's gone
pay the home directory still exists which is the behavior we wanted and expected.
Now let's the lead a user and their associated home directory so we can do dash d r k it says the user
was deleted.
That's right.
OK home directory is gone.
OK now let's test the functionality that we have built into our script of operating on multiple users
that are supplied as arguments to the script.
And also let's test the ability to create archives of these user accounts.
So let's do this.
We'll use Dashti for delete or to remove their home directory and archive it before it gets removed
and we'll give them these two users.
OK.
It says processing user Alyque G creating directory forward slash archive.
Now that is the directory that we're going to store these archive files in.
And again that doesn't come by default on a Linux system.
So we had to create it herself in our script and it says it's archiving the whole Mallik directory to
archive good PDZ.
And then it says the account was deleted and then it moves on to the next account.
Peter archive and delete as well.
So let's make sure the accounts and home directories are gone.
The account is gone.
For Peter M. has also gone.
Just check these both at once here.
Hey no home directories but let's make sure the archives were in fact created.
Hey there we have to.
The files one for each account.
Let's look at the contents of those archives.
Compress only to dash Z.
T to list the contents.
The will be verbose.
F allows us to specify the file.
This one first that looks good.
OK and we have the archive of both of those accounts.
So that wraps it up for this particular exercise.