Manually assigning Copilot for Microsoft 365 licenses to each user through the admin center is slow and error-prone for large organizations. You need a repeatable, scripted method to add or remove Copilot licenses across hundreds or thousands of users. The Microsoft Graph API provides a REST-based endpoint to manage license assignments directly from your automation tools. This article explains how to use the Graph API to provision Copilot licenses programmatically using PowerShell and Azure AD authentication.
Key Takeaways: Provisioning Copilot Licenses with Graph API
- Microsoft Graph API endpoint
/users/{id}/assignLicense: Assigns or removes Copilot licenses for a single user in one API call. - Azure AD app registration with
User.ReadWrite.Allpermission: Required to read user objects and modify license assignments via Graph API. - PowerShell script with
Connect-MgGraph: Authenticates to Microsoft Graph and runs bulk license operations using the Microsoft Graph PowerShell module.
Understanding the Copilot License SKU and Graph API Structure
Before you write any code, you need the exact product SKU identifier for Copilot for Microsoft 365. Each Microsoft 365 license plan has a unique GUID called the SKU ID. For Copilot, the SKU ID in Microsoft Graph is CFQ7TTC0LG0Z. This identifier is used in the addLicenses array when calling the assignLicense action.
The Microsoft Graph API uses the /users/{user-principal-name}/assignLicense endpoint. The request body contains two arrays: addLicenses and removeLicenses. To provision a Copilot license, you add the SKU ID to the addLicenses array. To remove it, you add the SKU ID to the removeLicenses array. The API processes both arrays in a single call, allowing you to replace existing licenses if needed.
The Graph API returns a User object with updated assignedLicenses property on success. If the call fails, the API returns an error with a code and message field describing the issue. Common errors include insufficient permissions, invalid SKU ID, or the user already having the license assigned.
Prerequisites for Using the Graph API
To call the Graph API, you need the following:
- An Azure AD tenant with a Copilot for Microsoft 365 subscription that has available licenses.
- An Azure AD application registered with the
User.ReadWrite.Alldelegated or application permission. For unattended scripts, use application permissions. - Admin consent granted to the application for the
User.ReadWrite.Allpermission. - A client secret or certificate for the application to authenticate without user interaction.
- The Microsoft Graph PowerShell module installed:
Install-Module Microsoft.Graph
Steps to Provision a Copilot License to a Single User
The following steps use the Microsoft Graph PowerShell module to assign a Copilot license to one user. Replace user@contoso.com with the actual user principal name and YOUR_TENANT_ID with your Azure AD tenant ID.
- Connect to Microsoft Graph
RunConnect-MgGraph -Scopes "User.ReadWrite.All" -TenantId "YOUR_TENANT_ID". Sign in with an admin account that has the Global Administrator or License Administrator role. The session remains active for the duration of the PowerShell window. - Retrieve the Copilot SKU ID
RunGet-MgSubscribedSku | Where-Object {$_.SkuPartNumber -eq "COPILOT_MICROSOFT_365"} | Select-Object SkuId, SkuPartNumber. This returns the GUID. The SKU part number for Copilot isCOPILOT_MICROSOFT_365. Copy theSkuIdvalue. - Assign the license to the user
Run the following script block:$userId = "user@contoso.com" $skuId = "YOUR_COPIED_SKU_ID" $addLicenses = @( @{ SkuId = $skuId DisabledPlans = @() } ) $removeLicenses = @() Set-MgUserLicense -UserId $userId -AddLicenses $addLicenses -RemoveLicenses $removeLicensesThe
DisabledPlansarray can include service plan IDs to disable specific features. For Copilot, you typically leave it empty. - Verify the license assignment
RunGet-MgUser -UserId $userId -Property AssignedLicenses | Select-Object -ExpandProperty AssignedLicenses. The output shows theSkuIdof the assigned Copilot license.
Bulk Provisioning Copilot Licenses from a CSV File
For large organizations, assign licenses to multiple users by reading a CSV file. The CSV must have a column named UserPrincipalName containing the user email addresses.
- Prepare the CSV file
Create a file namedusers.csvwith the following content:UserPrincipalName user1@contoso.com user2@contoso.com user3@contoso.comSave the file in your working directory.
- Import the CSV and loop through users
Run this script:$users = Import-Csv -Path ".\users.csv" $skuId = "YOUR_COPIED_SKU_ID" foreach ($user in $users) { $userId = $user.UserPrincipalName try { Set-MgUserLicense -UserId $userId -AddLicenses @(@{SkuId=$skuId;DisabledPlans=@()}) -RemoveLicenses @() Write-Host "License assigned to $userId" -ForegroundColor Green } catch { Write-Host "Failed to assign license to $userId : $_" -ForegroundColor Red } }The script processes each user and reports success or failure.
Removing a Copilot License Programmatically
To remove a Copilot license from a user, call the same endpoint but move the SKU ID to the removeLicenses array.
- Remove the license from a single user
Run:$userId = "user@contoso.com" $skuId = "YOUR_COPIED_SKU_ID" Set-MgUserLicense -UserId $userId -AddLicenses @() -RemoveLicenses @($skuId)The API removes the license immediately. The user loses access to Copilot features in Microsoft 365 apps.
- Bulk remove licenses from a CSV
Use the same CSV format and loop:$users = Import-Csv -Path ".\users.csv" $skuId = "YOUR_COPIED_SKU_ID" foreach ($user in $users) { $userId = $user.UserPrincipalName Set-MgUserLicense -UserId $userId -AddLicenses @() -RemoveLicenses @($skuId) }No error handling is shown here for brevity. Add try-catch blocks as in the bulk assign example.
Common Issues When Using Graph API for License Provisioning
API returns 403 Forbidden or 401 Unauthorized
The Azure AD application lacks the required User.ReadWrite.All permission or admin consent was not granted. Verify the permission is added to the app registration and admin consent is provided. In the Azure portal, go to App registrations > Your app > API permissions. Confirm User.ReadWrite.All is listed with a green checkmark for admin consent.
API returns 400 Bad Request with error code “InvalidSkuId”
The SKU ID provided does not match any licensed product in your tenant. Run Get-MgSubscribedSku to list all SKU IDs and their SkuPartNumber. Ensure you are using the correct GUID for Copilot. The SKU part number COPILOT_MICROSOFT_365 corresponds to the product CFQ7TTC0LG0Z.
License assignment succeeds but user does not see Copilot
Copilot features may take up to 24 hours to appear in Microsoft 365 apps. The license provisioning is immediate on the backend, but client-side propagation depends on the user’s app version and token refresh. Ask the user to sign out of all Microsoft 365 apps and sign back in. If the issue persists, verify the user has the latest Microsoft 365 Apps for enterprise version 2306 or later.
Graph API License Assignment vs Admin Center Manual Assignment
| Item | Graph API Programmatic Assignment | Admin Center Manual Assignment |
|---|---|---|
| Speed | Assigns licenses to hundreds of users in seconds via script | Requires clicking each user or uploading one CSV at a time |
| Repeatability | Script can run on a schedule or trigger from HR system | No built-in automation; must repeat steps manually |
| Error handling | Script logs failures per user and continues processing | Admin must manually check each user after assignment |
| Permission model | Uses Azure AD app permissions with admin consent | Requires Global Admin or License Admin role |
| Audit trail | All API calls logged in Azure AD audit logs | Changes logged in Microsoft 365 audit log |
Using the Graph API is the preferred method for organizations that need to automate license lifecycle management. The script-based approach reduces human error and provides a clear audit trail of all license changes.
You can now use Microsoft Graph API and PowerShell to provision Copilot licenses to individual users or in bulk from a CSV file. Start by registering an Azure AD app with the correct permissions and testing the script with a single user. For advanced scenarios, extend the script to read users from Microsoft Entra ID groups or an HR database. Use the Set-MgUserLicense cmdlet with the -RemoveLicenses parameter to deprovision licenses when users leave the organization.