How It Works
Configuration block
Two arrays at the top. $TargetGroupNames holds the exact AD group names you want to add people to. $EmailAddresses holds the email addresses of the users. Edit these before you run it. That’s the only thing you touch.
Deduplication
Before doing anything, the script strips duplicate email addresses from the array. Prevents the same user from being processed twice if you accidentally paste an address in more than once.
Group lookup with LDAP quote escaping
For each group name, the script runs Get-ADGroup with a filter. It also escapes any single quotes in the group name before building the LDAP filter string. Without that, a group name containing an apostrophe would throw a filter parse error.
Member cache
Before looping through users, it pulls the group’s current membership once with Get-ADGroupMember -Recursive and stores the distinguished names. Checking against that cached list is faster than hitting AD again for every user.
User lookup by email
Each email address is resolved to an AD user object using a Mail attribute filter. If no match is found, it warns you and moves on. It does not stop the whole run.
Membership check and add
If the user’s DN is already in the cached member list, the script says so and skips them. If they’re not a member, it calls Add-ADGroupMember. Success and failure both get logged to the console with color-coded output.
Usage
Requirements
- The
ActiveDirectoryPowerShell module must be installed. It comes with RSAT or is available on domain controllers. - The account running the script needs write permissions on the target AD groups. Read access alone won’t cut it.
How to run it
Edit the two arrays at the top of the script, then run it directly in a PowerShell session:
.Add-UsersToADGroups.ps1Code language: PowerShell (powershell)
No parameters. No flags. Configuration lives inside the script.
If you’re running this from a machine that isn’t domain-joined or needs a specific DC, you can pass -Server to the AD cmdlets, but you’d need to modify the script to do that.
Permissions
You need Modify rights on the group objects in AD. Domain Admins have this by default. Delegation also works if your AD team has set it up for specific OUs.
Caveats
- Group names must be exact. The filter uses the
Nameattribute. A trailing space or wrong case in your$TargetGroupNamesarray means the group lookup fails and the script skips it silently with an error message. Double-check names against AD before running.
- Lookup is by email, not username. If a user account doesn’t have the
Mailattribute populated in AD, the script won’t find them. It will warn you and skip that user. No partial matches, no fallback.
-Recursiveon large groups is slow. Pulling all members recursively on a group with thousands of nested members can take a while. The caching helps, but the initial pull still runs for every group in the list.
- No rollback. There’s no undo. If you add the wrong people to the wrong groups, you’re removing them manually. Test with a low-stakes group first.
- No logging to file. All output goes to the console. If you need an audit trail, pipe the output to a file or wrap the script in
Start-Transcript.
- Nested group membership. The
-Recursiveflag means a user who is a member through a nested group will show as already a member and won’t be added directly. Whether that matters depends on your setup.
Full Script
Import-Module ActiveDirectory
# ================= CONFIGURATION =================
# Target AD group names (EXACT names as seen in AD)
$TargetGroupNames = @(
"AD_Group_1",
"AD_Group_2",
"AD_Group_3",
"AD_Group_4",
"AD_Group_5"
)
# Email addresses to add
$EmailAddresses = @(
"[email protected]"
)
# =================================================
Write-Host "Connected to AD domain: $((Get-ADDomain).DNSRoot)" -ForegroundColor Green
Write-Host "Starting group membership updates..." -ForegroundColor Cyan
# Deduplicate emails
$EmailAddresses = $EmailAddresses | Select-Object -Unique
foreach ($GroupName in $TargetGroupNames) {
Write-Host "`nProcessing group: $GroupName" -ForegroundColor Cyan
# Escape single quotes for LDAP
$SafeGroupName = $GroupName -replace "'", "''"
try {
$Group = Get-ADGroup -Filter "Name -eq '$SafeGroupName'" -ErrorAction Stop
}
catch {
Write-Host "[ERROR] Group not found: $GroupName" -ForegroundColor Red
continue
}
# Cache group members ONCE
$GroupMemberDNs = (Get-ADGroupMember -Identity $Group -Recursive |
Select-Object -ExpandProperty DistinguishedName)
foreach ($Email in $EmailAddresses) {
try {
$User = Get-ADUser -Filter "Mail -eq '$Email'" -ErrorAction Stop
}
catch {
Write-Host "[WARNING] User not found for email: $Email" -ForegroundColor Yellow
continue
}
if ($GroupMemberDNs -contains $User.DistinguishedName) {
Write-Host "[INFO] $($User.SamAccountName) already a member" -ForegroundColor Gray
}
else {
try {
Add-ADGroupMember -Identity $Group -Members $User -ErrorAction Stop
Write-Host "[SUCCESS] Added $($User.SamAccountName) to $GroupName" -ForegroundColor Green
}
catch {
Write-Host "[ERROR] Failed to add $($User.SamAccountName): $_" -ForegroundColor Red
}
}
}
}
Write-Host "`nScript execution complete." -ForegroundColor GreenCode language: PowerShell (powershell)