๐ฅ Recipe ยท User & Group Management
Bulk Create M365 Users, Assign Licenses, and Export Credentials CSV
Provision a batch of Microsoft 365 users with licenses, group membership, directory roles, and a downloadable credentials CSV for handoff
Complexity
Intermediate
Impact
user-management + provisioning + licensing + automation + onboarding
Context
Why This Matters
This recipe handles end-to-end bulk onboarding for a cohort of new Microsoft 365 users โ a common workflow when onboarding a new team, pilot group, contractor batch, or beta user cohort. Creating users one-by-one in the admin center is slow and error-prone when you also need to assign licenses, add group memberships, delegate directory roles, and hand credentials back to the requester.
Run this when you need to:
- Onboard a batch of 3โ50+ users in a single operation
- Ensure consistent attributes (department, usage location, license SKU) across the cohort
- Produce a CSV of initial passwords for secure handoff to the requesting manager or the users themselves
- Assign the same directory role or group membership to all users in the batch
The workflow creates each user with a randomly-generated 16-character password, forces password change on first sign-in, assigns an available SKU (e.g. E5, Business Premium, Developer), adds each user to a target group, optionally grants a directory role, and exports a credentials.csv file that can be downloaded once.
Expected Outcomes
After running this recipe you will have:
- N new user accounts created in Microsoft Entra ID with consistent attributes (
displayName,userPrincipalName,givenName,surname,department,usageLocation) - A license assigned to each user from the specified SKU (licenses consumed from tenant availability)
- All users added as members of the target security or Microsoft 365 group
- Directory role granted (optional) โ e.g. User Administrator โ to each user
- A downloadable CSV file with columns
Name,Email/UPN,Initial Passwordfor secure handoff - Force-change-password-on-next-signin set on every account, so initial passwords are one-time use only
Risks & Considerations
โ ๏ธ Warnings & Gotchas
- CSV contains plaintext passwords. Treat the output file as a secret. Deliver via a secure channel (password manager vault, encrypted email, Teams private chat with expiration) and delete the local copy after handoff.
- Do not reuse the CSV. Once users sign in and change passwords, the values in the file are stale. Regenerate if needed.
- License availability. Check
consumedUnitsvsprepaidUnits.enabledon the target SKU before running. The script will fail partway through if the tenant runs out of seats. - UPN domain must be verified. If you use a custom domain in the UPN, it must be verified on the tenant (
isVerified: true) or user creation returns 400 Bad Request. - Usage location is required for licensing. The
usageLocationattribute (ISO 3166-1 alpha-2, e.g.US,GB,DE) must be set before callingassignLicense, or the call returns an error. - Directory role assignment is privileged. Granting User Administrator or similar roles is a privileged action โ confirm the business justification and log the change in your change-management system.
- Avoid hardcoding passwords in scripts. The script below generates them at runtime and never persists them outside the CSV artifact.
- Idempotency. Re-running the script with the same UPNs will fail with 409 Conflict. Add a pre-check or an
-IfNotExistsflag if you need re-runnable behavior.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| User.ReadWrite.All | Create user accounts, set password profiles, update attributes |
| Directory.ReadWrite.All | Assign licenses and directory roles |
| Group.ReadWrite.All | Add users to the target group |
| Organization.Read.All | List subscribed SKUs to find the license skuId |
| RoleManagement.ReadWrite.Directory | Assign directory roles such as User Administrator |
The fastest way to get this done: just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex Pro
Bulk create users via the Microsoft 365 admin center
The admin center supports bulk creation via CSV upload. This is the best GUI path when you have 5+ users.
Step 1 โ Prepare your input CSV
Create a CSV with the M365 admin center's required columns:
User name,First name,Last name,Display name,Job title,Department,Office number,Office phone,Mobile phone,Fax,Address,City,State or province,ZIP or postal code,Country or region
alice.smith@contoso.com,Alice,Smith,Alice Smith,,Beta Users,,,,,,,,,United States
bob.jones@contoso.com,Bob,Jones,Bob Jones,,Beta Users,,,,,,,,,United StatesStep 2 โ Upload the CSV
- Sign in to admin.microsoft.com as a Global admin or User admin
- Navigate:
- Click Upload a CSV file and select your prepared file
- Under Set user settings, choose:
- Sign-in status: Allow user to sign in
- Product licenses: Select your target SKU (e.g. Microsoft 365 E5)
- Click Next, review the summary, and click Create users
- Microsoft 365 generates temporary passwords and offers a Download results CSV โ this is your credentials file. Download it immediately; it is not retrievable later.
Step 3 โ Add users to a group
- Navigate:
- Open the target group (or create a new one with Add a group)
- Go to the Members tab โ View all and manage members โ Add members
- Search and add each new user
Step 4 โ Assign a directory role (optional)
- Go to entra.microsoft.com โ
- Search for the target role (e.g. User Administrator) and open it
- Click Add assignments, select the new users, and confirm
Step 5 โ Secure handoff
Store the downloaded credentials CSV in a password manager or encrypted vault, share with the requester via a secure channel, and delete your local copy.
Automate with Microsoft Graph
The Graph API flow for each user is: create โ assign license โ add to group โ assign role. Wrap these in a loop over your input list.
1. Discover prerequisites (once)
Get the SKU id for the license you want to assign:
GET https://graph.microsoft.com/v1.0/subscribedSkusResponse: find the entry whose skuPartNumber matches your target (e.g. SPE_E5, DEVELOPERPACK_E5). Note the skuId GUID.
Get the group id:
GET https://graph.microsoft.com/v1.0/groups?$filter=displayName eq 'Beta Users'&$select=id,displayNameGet the directory role id (activate the template first if not already active):
GET https://graph.microsoft.com/v1.0/directoryRolesFind the entry with displayName: "User Administrator" and note its id.
2. Create each user
POST https://graph.microsoft.com/v1.0/users
Content-Type: application/json
{
"accountEnabled": true,
"displayName": "Alice Smith",
"givenName": "Alice",
"surname": "Smith",
"mailNickname": "alice.smith",
"userPrincipalName": "alice.smith@contoso.onmicrosoft.com",
"department": "Beta Users",
"usageLocation": "US",
"passwordProfile": {
"forceChangePasswordNextSignIn": true,
"password": "<randomly generated 16-char password>"
}
}Response 201 Created returns the new user's id (GUID). Capture it for the next steps.
3. Assign a license
POST https://graph.microsoft.com/v1.0/users/{userId}/assignLicense
Content-Type: application/json
{
"addLicenses": [ { "skuId": "{skuId}" } ],
"removeLicenses": []
}4. Add to group
POST https://graph.microsoft.com/v1.0/groups/{groupId}/members/$ref
Content-Type: application/json
{
"@odata.id": "https://graph.microsoft.com/v1.0/users/{userId}"
}5. Assign directory role (optional)
POST https://graph.microsoft.com/v1.0/directoryRoles/{roleId}/members/$ref
Content-Type: application/json
{
"@odata.id": "https://graph.microsoft.com/v1.0/users/{userId}"
}6. Build the credentials CSV
As you iterate, append displayName,userPrincipalName,password to an in-memory buffer, then write the buffer to a .csv file at the end of the batch. Do not persist passwords anywhere else.
Throttling: Graph rate limits apply. For batches over ~20 users, add a small delay (200โ500 ms) between requests, or use $batch with a batch size of 4โ5 create operations.
PowerShell: end-to-end bulk onboarding
The Microsoft.Graph PowerShell SDK provides typed cmdlets for all the Graph calls above. The downloadable script below accepts a CSV of users, a license SKU part number, a target group, and an optional directory role, then emits a credentials CSV.
Prerequisites
- PowerShell 7+ (recommended) or Windows PowerShell 5.1
- Modules:
Microsoft.Graph.Users,Microsoft.Graph.Groups,Microsoft.Graph.Identity.DirectoryManagementInstall-Module Microsoft.Graph -Scope CurrentUser - A Global Administrator or User Administrator + License Administrator + Groups Administrator account
Input CSV format (users.csv)
DisplayName,GivenName,Surname,MailNickname,UserPrincipalName
Alice Smith,Alice,Smith,alice.smith,alice.smith@contoso.onmicrosoft.com
Bob Jones,Bob,Jones,bob.jones,bob.jones@contoso.onmicrosoft.comRun
.\New-BulkM365Users.ps1 `
-InputCsv .\users.csv `
-LicenseSkuPartNumber 'SPE_E5' `
-GroupName 'Beta Users' `
-Department 'Beta Users' `
-UsageLocation 'US' `
-DirectoryRoleName 'User Administrator' `
-OutputCsv .\credentials.csvWhat the script does
- Connects to Graph with the required scopes
- Resolves the SKU id, group id, and (optionally) activates and resolves the directory role
- For each input row:
- Generates a cryptographically random 16-character password
- Creates the user with
forceChangePasswordNextSignIn = $true - Assigns the license
- Adds the user to the group
- Assigns the directory role (if specified)
- Appends
Name,Email,InitialPasswordto the output CSV
- Writes a summary and the path to the credentials CSV
Errors on individual users are caught and logged; the script continues with the remaining users rather than failing the whole batch.
Next steps