Managing permissions and group memberships in SharePoint is critical for effective collaboration and security. Automating the process of adding users to SharePoint groups using PowerShell saves time and reduces manual errors compared to adding people one at a time through the browser. Here’s how to do it step by step, with practical use cases and sample scripts.
In this post: Prerequisites · Step-by-Step Guide · Add Users from a CSV File · Add-PnPUserToGroup vs. Add-PnPGroupMember · Error Handling · The reverse operation: removing users · When would you actually use this? · Related reading
Prerequisites
Before diving into the scripts, ensure you have the following:
- Appropriate administrative permissions for the target SharePoint site.
- PnP PowerShell Module installed. You can install it via PowerShell:
Install-Module -Name PnP.PowerShell
- Access to the SharePoint Online or on-premises environment you’re scripting against.
Step-by-Step Guide
1. Connect to SharePoint
To interact with SharePoint, establish a connection using PnP PowerShell.
For SharePoint Online:
Connect-PnPOnline -Url "https://yourtenant.sharepoint.com/sites/YourSite" -Interactive
For SharePoint On-Premises:
Connect-PnPOnline -Url "http://yourserver/sites/YourSite" -Credentials (Get-Credential)
2. Add a Single User to a Group
Here’s a script to add one user to a specific group:
# Variables
$siteUrl = "https://yourtenant.sharepoint.com/sites/YourSite"
$groupName = "Site Members"
$userEmail = "user@domain.com"
# Connect to SharePoint
Connect-PnPOnline -Url $siteUrl -Interactive
# Add user to the group
Add-PnPUserToGroup -Group $groupName -LoginName $userEmail
Write-Host "User $userEmail added to $groupName successfully."
3. Add Multiple Users to a Group
To bulk-add users, use the following script:
# Variables
$siteUrl = "https://yourtenant.sharepoint.com/sites/YourSite"
$groupName = "Site Members"
$userEmails = @("user1@domain.com", "user2@domain.com", "user3@domain.com")
# Connect to SharePoint
Connect-PnPOnline -Url $siteUrl -Interactive
# Add users to the group
foreach ($email in $userEmails) {
Add-PnPUserToGroup -Group $groupName -LoginName $email
Write-Host "User $email added to $groupName."
}
Add Users from a CSV File
This script reads user emails from a CSV file and adds them to a group. Ensure the CSV file contains a column named Email.
Example CSV content:
Email
user1@domain.com
user2@domain.com
user3@domain.com
PowerShell script:
# Variables
$siteUrl = "https://yourtenant.sharepoint.com/sites/YourSite"
$groupName = "Site Members"
$csvPath = "C:\Users\YourUsername\users.csv"
# Connect to SharePoint
Connect-PnPOnline -Url $siteUrl -Interactive
# Read CSV and add users
$users = Import-Csv -Path $csvPath
foreach ($user in $users) {
Add-PnPUserToGroup -Group $groupName -LoginName $user.Email
Write-Host "User $($user.Email) added to $groupName."
}
Add-PnPUserToGroup vs. Add-PnPGroupMember
Worth knowing before scripting this against a production group at any scale: Add-PnPUserToGroup, used throughout this post, has been superseded by Add-PnPGroupMember in current PnP PowerShell — the older cmdlet still works, but new scripts should generally reach for the newer name. Functionally the two behave the same for the scenarios above; the practical reason to care is that PnP’s own documentation and community examples are gradually shifting toward Add-PnPGroupMember, so troubleshooting help and current syntax references are easier to find under that name going forward.
The more immediate gotcha, with either cmdlet name: adding a user who’s already a member of the target group can fail with a 400 Bad Request instead of silently succeeding or skipping. That matters directly for the bulk and CSV scripts above — a list that’s been run before, or that overlaps with people already in the group, can partially fail partway through the loop. Checking existing membership first avoids it:
$existingMembers = (Get-PnPGroupMember -Identity $groupName).Email
foreach ($email in $userEmails) {
if ($existingMembers -contains $email) {
Write-Host "$email is already a member of $groupName -- skipping."
continue
}
Add-PnPUserToGroup -Group $groupName -LoginName $email
Write-Host "User $email added to $groupName."
}
This is worth building into the CSV-import script above by default, not just the ones where a duplicate seems likely — a CSV re-run after fixing a typo in one row is a completely normal workflow, and it shouldn’t fail the whole batch over the rows that already succeeded the first time.
Adding a user who’s already a group member can fail with a 400 error rather than silently succeeding — check membership with Get-PnPGroupMember first, especially in a script that might get re-run.
Error Handling
To handle errors gracefully, include try-catch blocks in your script:
try {
Add-PnPUserToGroup -Group $groupName -LoginName $userEmail
Write-Host "User $userEmail added successfully."
} catch {
Write-Host "Error adding user $userEmail: $_"
}
The reverse operation: removing users
The “periodic access review” use case further down needs this half as much as the adding side — an offboarding or role-change process that only ever adds people to groups isn’t actually managing access, it’s just accumulating it. Remove-PnPGroupMember is the direct counterpart to Add-PnPGroupMember covered above (both are the current names; Remove-PnPUserFromGroup is the older equivalent, same relationship as the add-side cmdlet pair):
# Remove one user from a group
Remove-PnPGroupMember -Group $groupName -LoginName $userEmail
# Bulk-remove, using the same list-driven pattern as the add scripts above
foreach ($email in $userEmails) {
Remove-PnPGroupMember -Group $groupName -LoginName $email
Write-Host "User $email removed from $groupName."
}
Unlike adding a duplicate, removing someone who isn’t currently a member doesn’t reliably throw the same way — worth checking membership first with the same Get-PnPGroupMember pattern from the section above regardless, since the goal of a periodic review script is knowing exactly who changed, not just running commands and hoping they landed.
When would you actually use this?
- Onboarding adds several people at once, and adding each one through the browser’s group membership page is slower than running one script against a list of emails.
- A new project needs its team added to a project-specific SharePoint group in one shot, not person by person.
- A periodic access review needs group membership updated in bulk — additions and removals — on a schedule, not as a manual monthly task.
- User details already live in an HR system or a CSV export — feeding that directly into the script above skips re-typing the same list of names.
Related reading
- All about SharePoint Permission Roles — what the groups covered here actually grant once someone’s added.
- Get SharePoint Site Users: Implementations and Use Cases — the reverse operation, auditing who’s already got access.
Using PowerShell scripts for managing SharePoint group memberships is a powerful way to streamline operations and minimize errors. Whether you’re handling individual users or large batches, these scripts offer flexibility and efficiency.
App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning


