How to Add or Remove Users from Active Directory Groups
Active Directory has been one of my favourite tools in which I could automate repetitive processes. Starting from user additions to user deletions, clean-up, audits, all the way to new hire and user account termination process. Active Directory is a fantastic avenue for automation. And, who does not like hyper-efficient Active Directory administrators?
I thought I would start a series on Active Directory automations. Today, we look at adding users to and removing users from Active Directory groups.
As usual, our scripts must have loose coupling. This means no hard-coding anything. Okay, where did that come from? Over the last decade that I have been dealing with scripts, I have seen those that have credentials hard-coded more than I could tolerate.
Never hard-code credentials.
Or any data.
While keeping the code separate from data is the ideal setup, it may not always be possible to do so. In case of scripts what may be acceptable, is write functions for every piece of work that you want the script to do, and then, write a master function that ties them all together. This is the approach I have been using for some time now, and I find it flexible and scalable.
The problem
Now that we have the couple of pieces of philosophy out of the way, let us look at what we started this post for: Addition or removal of users from AD groups.
Here is what we want:
- A script that:
- Searches for users and groups across all domains in the environment
- Adds a user to the specified groups
- Tells if the user is already part of a specified group
- A script that:
- Searches for users and groups across all domains in the environment
- Removes a user from the specified groups
- Tells if the user does not exist in a specified group
The script
I am not going to keep you waiting for the script. You can also find the script in my GitHub repository.
|
|
How to use it
Okay, glad you are back here. If you read the script, you would see that there are four functions in it. If you run the script by hitting F5 or ‘Run with PowerShell’, you will see that nothing happens. Well, welcome to the world of PowerShell!
To see how to run PowerShell scripts, visit this post. In this case, you will have to save the script somewhere on your PC and run:
. '\\path\to\ADUserGroupManipulation.ps1'
This would load the functions into the session (that leading dot is important). Then, you would need to run commands like:
Add-ADUserToGroup -Identity 'JohnDoe' -GroupName 'GroupOne', 'GroupTwo' -Domains 'first.domain.com', 'second.domain.com' -Credential 'DOM\U739937'
Or:
Remove-ADUserFromGroup -Identity 'JohnDoe' -GroupName 'GroupOne', 'GroupTwo' -Domains 'first.domain.com', 'second.domain.com' -Credential 'DOM\U739937'
How it works
If you look at the script, you will see that it has four functions, which broadly have two actions:
- Finding the object (user or group)
- Adding / removing the user to / from the groups
Why have we written four functions for what a single script or function can handle? Loose coupling. You can—when you decide at a later date—reuse these functions without modifications.
The general rule of thumb is to make one function do no more than one task.
Finding the object
Most environments that I have worked with have more than one domain. In environments with a single domain, finding users should not be an issue at all. But in other environments, the Get-ADUser
cmdlet may cause errors, when you do not specify the domain name.
If you know the list of domains to look in, you can handle this with a simple try
–catch
block. The function loops through the domains and tries to find the user in the domain, using the Get-ADUser
cmdlet with the Server
parameter. When the execution reaches the catch
block, it merely writes a verbose message, after which, it goes to the next item in the loop.
|
|
When it finds the user, the operation breaks out of the loop.
|
|
This brings us to a caveat:
If a user exists with the same SAM in more than one domain, the script will assume that you are talking about the user object it finds first. To work around this, you can specify the domains in the sequence that you want to run the search in. If you have a group with the same name in more than one domain, this problem gets compounded. Ideally, you should not create groups with the same name in different domains.
Once the function finds the object (user or group), it returns the entire object for use by the calling function. (You need not use the return
keyword.)
|
|
Adding or removing the user
One of the requirements is that the script tell us when it finds that the user is already in a particular group in case of user addition, or is not in a particular group in case of removal.
This function first finds the user by calling the Find-ADUser
function. The function breaks out of execution if it does not find the user. Yes, you can use an if
branch with a positive condition, but I think the negative condition is much more readable.
|
|
Readability is important.
Next, the function looks for the user membership. Yes, you can incorporate the Properties
parameter in the Find-
functions, but when you are looking to reuse it, the operation would be unnecessary. I like to keep the functions generic. No harm in performing another query into the Active Directory.
Also, this time, you do not need to use the Server
parameter, because the returned object has the information that the Get-ADUser
cmdlet needs.
|
|
The function then loops through each of the specified groups. It checks if the user is already part of the group, and if they are, it shows a warning. If not, it tries to find the group in each of the specified domains. Once found, the function adds the user to the group. This is where it uses the credentials.
|
|
A note on credentials
No, I have already said you should not hard-code credentials in a script.
When you make a function accept the credential as a parameter, you must remember the following:
- The credential should be a credential object. We do this by specifying the type as
[System.Management.Automation.PSCredential]
. - We must check if the user passes a null value. We do this using
[ValidateNotNull()]
. When you do that, the user will get an error when they try to pass a null value. - If we want to be able to pass in the username and make the function prompt for a password, we specify the type also as
[System.Management.Automation.Credential()]
. - And in the end, we also want to specify the default value as
Empty
, so that you avoid the error caused by[ValidateNotNull()]
.
|
|
Summary
Hopefully, this gives you a picture of how you can handle addition or removal of users to or from AD groups. We look at how we can find an AD user or group across more than one domains. We use a modular approach to handle the tasks, and create functions with loose coupling, to enable us to reuse the functions. If you would like to know how modularity dramatically improves scalability, click here to see it in practice.
Of course, we can tune these functions according to the requirements. Every environment is different. Efficiency is all about tuning the script to the environment that it would run in. I have kept this solution as generic as possible.
Still, if you have any questions or have a better way to handle the request, please reach out to me on Twitter and share your thoughts.
Take care.