Bulk User Operations with PowerShell and CSV
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
Managing Microsoft Entra ID Users via Bulk Operations: A Comprehensive Guide
Introduction: Why Bulk Management Matters
In a modern enterprise environment, the identity lifecycle—the process of creating, updating, and removing user accounts—is a constant activity. Whether you are onboarding a new batch of employees, migrating users from an on-premises Active Directory, or performing a mass update of department attributes, performing these tasks manually through the Microsoft Entra admin center (formerly Azure AD) is not only inefficient but also highly prone to human error. When you have five users to create, the web portal is acceptable; when you have five hundred or five thousand, it becomes a bottleneck that drains your administrative time and risks inconsistent data.
Bulk operations using PowerShell and CSV files allow you to treat identity management as a programmatic task. By automating these processes, you ensure that every user is created with the same security groups, licenses, and naming conventions applied consistently. This approach is essential for maintaining compliance, enforcing organizational standards, and reducing the time-to-productivity for new hires. In this lesson, we will explore the mechanics of using the Microsoft Graph PowerShell SDK to manage identities at scale, moving beyond simple manual entry into the realm of professional identity engineering.
The Foundation: Preparing Your Environment
Before we can execute bulk scripts, we must ensure our workstation is properly configured to communicate with Microsoft Entra ID. The legacy Azure AD PowerShell modules (MSOnline and AzureAD) are deprecated. We now rely exclusively on the Microsoft Graph PowerShell SDK. This SDK is modular, secure, and provides deeper access to the full range of Microsoft 365 services.
Installing and Connecting to Microsoft Graph
To get started, you need to install the Microsoft Graph modules. It is recommended to install the specific modules you need rather than the entire suite to keep your environment clean. Open PowerShell as an Administrator and run the following commands:
# Install the necessary modules
Install-Module Microsoft.Graph.Users -Scope CurrentUser
Install-Module Microsoft.Graph.Groups -Scope CurrentUser
# Connect to the service with the required permissions
Connect-MgGraph -Scopes "User.ReadWrite.All", "Group.ReadWrite.All"
Note: When you run
Connect-MgGraph, a browser window will open, prompting you to sign in with your administrator credentials. Always use a dedicated service account or your own administrative account with Multi-Factor Authentication (MFA) enabled. Never store credentials in plaintext inside your scripts.
Once connected, you can verify your session by running Get-MgContext. This command confirms your current tenant ID and the scopes (permissions) you have granted to the session.
Structuring Your Data: The CSV Format
The secret to successful bulk operations is the data source. A CSV (Comma Separated Values) file is the industry standard for this task because it is lightweight, readable by both humans and machines, and easily exported from HR systems like Workday or SAP.
Designing a Scalable CSV Schema
When creating a CSV for user onboarding, your headers should map directly to the properties required by the Microsoft Graph API. For a standard user creation script, your CSV should include at least the following columns:
- DisplayName: The full name of the user.
- UserPrincipalName (UPN): The login ID (e.g., [email protected]).
- MailNickname: The alias used for email (usually the part before the @).
- PasswordProfile: A temporary password that requires a change on first login.
- Department: Used for organizational grouping.
- UsageLocation: Required for assigning Microsoft 365 licenses.
Here is an example of what your users.csv file should look like:
DisplayName,UserPrincipalName,MailNickname,Department,UsageLocation,Password
Jane Doe,[email protected],jdoe,Engineering,US,TemporaryP@ss123
Bob Smith,[email protected],bsmith,Marketing,US,TemporaryP@ss123
Tip: Always use a text editor like VS Code or Notepad++ to create your CSV files. Excel can sometimes add hidden characters or formatting that interferes with PowerShell’s ability to parse the file correctly.
Implementing Bulk User Creation
Now that we have our environment ready and our data structured, we can write the script to process the CSV. The logic involves reading the file, iterating through each row, and calling the New-MgUser cmdlet.
The Bulk Creation Script
# Import the CSV data
$UserData = Import-Csv -Path "C:\Temp\users.csv"
# Iterate through each user in the CSV
foreach ($Row in $UserData) {
Write-Host "Creating user: $($Row.DisplayName)" -ForegroundColor Cyan
# Define the user parameters
$Params = @{
DisplayName = $Row.DisplayName
UserPrincipalName = $Row.UserPrincipalName
MailNickname = $Row.MailNickname
AccountEnabled = $true
UsageLocation = $Row.UsageLocation
PasswordProfile = @{
Password = $Row.Password
ForceChangePasswordNextSignIn = $true
}
}
# Execute the creation command
try {
New-MgUser @Params -ErrorAction Stop
Write-Host "Successfully created $($Row.UserPrincipalName)" -ForegroundColor Green
}
catch {
Write-Error "Failed to create $($Row.UserPrincipalName): $($_.Exception.Message)"
}
}
Understanding the Script Logic
The script uses a "splatting" technique (the @Params variable). This is a best practice in PowerShell because it keeps your code clean and readable. Instead of writing a long line of code with many arguments, you define a hash table that contains all the required parameters and pass it to the command using the @ symbol.
The try/catch block is critical for enterprise operations. If one user fails to create—perhaps because the UPN is already in use—the script will not crash. Instead, it will log the error and proceed to the next user in the list, allowing you to review the failures after the script finishes.
Advanced Bulk Operations: Updating Existing Users
Bulk operations are not limited to creation. Often, you need to update attributes for existing employees, such as changing their department or updating their manager. The process is similar, but instead of New-MgUser, we use Update-MgUser.
Updating User Attributes via CSV
Suppose you have a list of users whose department has changed due to a reorganization. Your CSV would contain the UserPrincipalName and the NewDepartment.
$Updates = Import-Csv -Path "C:\Temp\updates.csv"
foreach ($Row in $Updates) {
Update-MgUser -UserId $Row.UserPrincipalName -Department $Row.NewDepartment
Write-Host "Updated $($Row.UserPrincipalName) to department $($Row.NewDepartment)"
}
This simple pattern can be extended to handle almost any user property. The key is to ensure that the identifier (the UserId) is unique and correct before attempting the update.
Managing Groups in Bulk
Managing group memberships is another frequent task. You might need to add a list of users to a "Security-All-Staff" group or assign them to specific project teams.
Adding Users to Groups
To add users to a group, you need the GroupId and the UserId. You can look these up dynamically if you only have the names.
$GroupId = "a1b2c3d4-e5f6-7890-abcd-1234567890ab"
$UsersToAdd = Import-Csv -Path "C:\Temp\group_members.csv"
foreach ($User in $UsersToAdd) {
$UserObj = Get-MgUser -UserId $User.UPN
New-MgGroupMemberByRef -GroupId $GroupId -DirectoryObjectId $UserObj.Id
}
Callout: Bulk Creation vs. Bulk Update When creating users, you are defining the identity from scratch, which requires mandatory fields like
PasswordProfileandAccountEnabled. When updating users, you are modifying existing objects. Always verify the existence of the user object usingGet-MgUserbefore attempting an update to prevent "Object Not Found" errors.
Best Practices for Bulk Identity Operations
Automation is powerful, but it requires discipline. Follow these guidelines to ensure your bulk operations are safe and effective.
1. The "Test-First" Methodology
Never run a script against your entire production CSV on the first try. Create a test.csv file with only two or three entries. Run the script against this small set to ensure the formatting is correct and the logic produces the desired outcome in the Entra admin center.
2. Logging and Auditing
Don't rely on the console output. Redirect your output to a log file so you have a record of what happened. Use Start-Transcript at the beginning of your script to capture everything that occurs during the session.
Start-Transcript -Path "C:\Logs\UserCreation_$(Get-Date -Format 'yyyyMMdd').txt"
# ... run your script ...
Stop-Transcript
3. Error Handling
As shown in our script examples, always wrap your operations in try/catch blocks. This ensures that a single row with a typo doesn't halt a massive operation.
4. Use Service Principals for Production
If you are running these scripts as a scheduled task (e.g., syncing from a legacy HR system nightly), do not use a user account. Use an Azure App Registration (Service Principal) with the minimum required permissions (Principle of Least Privilege).
Common Pitfalls and How to Avoid Them
Even experienced administrators can fall into traps when dealing with bulk operations. Here are the most common mistakes:
- The "Slow" Loop: If you are processing thousands of users, a simple
foreachloop can take a very long time because it waits for each API call to complete. For massive operations, look into theForEach-Object -Parallelcommand in PowerShell 7, which allows you to process multiple users simultaneously. - Ignoring Throttling: Microsoft Graph API has rate limits. If you fire too many requests at once, the API will return a 429 "Too Many Requests" error. The Microsoft Graph SDK handles some of this automatically, but for extremely large batches, it is good practice to add a small
Start-Sleep -Milliseconds 200inside your loop to keep the request rate steady. - Data Quality Issues: Garbage in, garbage out. If your CSV has trailing spaces, missing UPNs, or invalid email formats, your script will fail. Always perform data validation at the start of your script before calling the API.
- Lack of Cleanup: If you create a test user, remember to delete it. Leaving "test_user_01" in your directory is a security risk and clutters your environment.
Comparison: PowerShell vs. Portal vs. Bulk Upload Tool
It is important to understand when to use which tool.
| Method | Best For | Pros | Cons |
|---|---|---|---|
| Entra Portal | Single user changes | Easy, visual, no code | Slow, prone to error, no audit trail |
| Bulk Upload Tool | Simple creation/deletion | User-friendly, built-in | Limited attributes, no complex logic |
| PowerShell/Graph | Complex, recurring tasks | Powerful, repeatable, scalable | Requires coding skills, steeper learning curve |
Security Considerations for Identity Management
When you are managing users and groups, you are managing the keys to the kingdom. Any script that has the power to create users or add them to groups is a high-value target for attackers.
- Restrict Access: Only store these scripts in secure, version-controlled repositories like private GitHub or Azure DevOps instances. Never leave scripts on a shared file server where unauthorized users might access them.
- Use Managed Identities: If your scripts run on an Azure Virtual Machine, use a Managed Identity instead of storing a client secret in your script. A Managed Identity is automatically rotated and managed by Azure, removing the risk of credential leakage.
- Review Permissions: Regularly check the permissions assigned to your App Registrations. If a script only needs to update user departments, do not give it
User.ReadWrite.All. Look for more granular permissions if they exist.
Step-by-Step: Troubleshooting a Failed Bulk Operation
If your script fails, follow this systematic approach to identify the issue:
- Check the Error Message: The PowerShell console will usually give you a specific error code. If you see "Authorization_RequestDenied," your service principal lacks the necessary permissions. If you see "Request_ResourceNotFound," the ID you are referencing does not exist.
- Verify the CSV Input: Open your CSV in a text editor. Check for invisible characters or unexpected line breaks. Ensure the column headers match your script variables exactly (e.g.,
UserPrincipalNamevsUPN). - Test the Single Command: Isolate the line of code that is failing. Take one row from your CSV and manually run the command in the PowerShell console, replacing the variables with the actual values. This usually reveals the exact syntax or logic error.
- Check the Graph Explorer: If you are unsure what properties are available or how the API expects the data, use the Microsoft Graph Explorer (a web-based tool for testing API calls). You can mock up the request there to see if it succeeds.
Summary and Key Takeaways
Managing Microsoft Entra ID users and groups at scale is a core competency for any identity engineer. By moving from manual portal interactions to automated PowerShell scripts, you move from "doing work" to "engineering solutions."
Key Takeaways:
- Automation is Essential: Use PowerShell and CSVs to eliminate the manual overhead of repetitive identity tasks. This leads to higher accuracy and better organizational consistency.
- The Microsoft Graph SDK is the Standard: Abandon legacy modules and embrace the Microsoft Graph PowerShell SDK. It provides the most secure and comprehensive interface for interacting with Entra ID.
- Adopt Defensive Coding: Always use
try/catchblocks, implement logging, and validate your data before executing changes. Never run a large-scale script without testing on a small sample first. - Prioritize Security: Treat your automation scripts as sensitive assets. Use Managed Identities or secure credential storage, and always apply the principle of least privilege to your service principals.
- Understand the Lifecycle: Bulk operations are not just for creation. Think about how you will handle updates, group memberships, and account deletions as part of a complete identity lifecycle management strategy.
- Handle Throttling and Errors: Real-world scripts must be resilient. Build in delays, error handling, and robust logging to ensure that your processes are reliable and easy to debug when things go wrong.
- Continuous Improvement: Keep your scripts in a version-controlled system. As your organization grows, revisit your scripts to optimize them for performance and security.
By mastering these techniques, you will not only save time but also create a more resilient and secure environment for your users. Start small, build your library of scripts, and treat your identity infrastructure as code. This mindset will serve you well as you scale your operations in the cloud.
Common Questions (FAQ)
Q: Can I use Excel to edit my CSV files? A: While you can, be careful. Excel often changes date formats or adds invisible formatting. If you use Excel, always "Save As" a CSV (Comma Delimited) file and then open that file in a plain text editor to ensure it looks exactly as you expect before running your script.
Q: How do I know which permissions I need for a specific task?
A: The Microsoft Graph documentation for each endpoint lists the required permissions. For example, if you look up the New-MgUser documentation, it will tell you that you need User.ReadWrite.All or Directory.ReadWrite.All.
Q: What if I have 10,000 users to update? A: For very large sets, consider breaking the CSV into smaller chunks (e.g., 1,000 users per file). This makes it easier to manage, monitor, and retry if a specific batch fails.
Q: Is there a built-in way to schedule these scripts? A: Yes. You can use Azure Automation Runbooks to store and execute your PowerShell scripts on a schedule. This is a common pattern for HR-driven identity synchronization.
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons