To delete multiple Microsoft Teams created dynamically by a PHP script, you must use the Microsoft Graph API with the
Group.ReadWrite.All permission scope. This article explains how to authenticate via Service Principal, iterate through your target teams using their unique identifiers, and execute HTTP DELETE requests to remove them programmatically.
Understanding Permissions and Authentication
The most common error when attempting to delete Teams is using incorrect permissions. The
TeamSettings.ReadWrite.All permission is insufficient for deletion tasks. You must request the
Group.ReadWrite.All application permission in your Azure AD App Registration. This permission grants the necessary rights to manage the underlying Microsoft 365 Group that backs each Team.
Authentication in PHP typically involves acquiring an access token using the client credentials flow. This method is ideal for background scripts because it does not require user interaction. You will need your Tenant ID, Client ID, and Client Secret from the Azure portal. The token endpoint is
https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token. Ensure that your application has been granted admin consent for these permissions before running the script. Without proper consent, the API will return a 403 Forbidden error even if the code logic is correct.
Identifying Teams to Delete
Before deleting, you must identify which teams were created by your specific script. Hardcoding team IDs is not scalable. Instead, store the team IDs or group IDs in a database or a configuration file alongside the project metadata. If you did not store this information, you can query the Microsoft Graph API to list all groups. Use the endpoint
GET https://graph.microsoft.com/v1.0/groups with a filter based on display name patterns or creation dates.
For example, if your dynamic teams follow a naming convention like "Project-Alpha", you can filter results using
$filter=startswith(displayName,'Project-Alpha'). This ensures you only target the relevant resources. It is critical to distinguish between the Team ID and the Group ID. While they are often the same GUID, relying on the Group ID is safer for deletion operations because the underlying resource is a Group object. Always verify the type of the resource before proceeding to avoid accidental deletions of non-team entities.
Implementing the Deletion Logic in PHP
PHP provides robust libraries for making HTTP requests. Using cURL or Guzzle allows you to interact with the Graph API efficiently. Below is a conceptual structure for the deletion process. First, obtain the access token. Then, loop through your list of target group IDs. For each ID, send a DELETE request to
https://graph.microsoft.com/v1.0/groups/{group_id}.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://graph.microsoft.com/v1.0/groups/" . $groupId);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer " . $accessToken,
"Content-Type: application/json"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode == 204) {
echo "Team deleted successfully.";
} else {
echo "Failed to delete team. Error: " . $response;
}
Handling errors is crucial. A 204 No Content response indicates success. Any other status code requires logging and potentially retrying the operation. Common errors include
Request_BadRequest if the ID is invalid, or
Forbidden if permissions are missing. Implementing exponential backoff for transient network errors can improve reliability during bulk operations.
Bulk Operations and Rate Limiting
When deleting hundreds of teams, you must respect Microsoft Graph rate limits. Exceeding these limits results in 429 Too Many Requests responses. To mitigate this, introduce delays between requests or batch your operations where possible. However, deletion is not a batchable operation in the same way as creating items. Each team must be deleted individually.
Consider implementing a queue system within your PHP script. Process deletions in chunks, such as ten teams at a time, with a pause between batches. This approach prevents overwhelming the API and reduces the risk of timeouts. Additionally, log every successful deletion to ensure idempotency. If the script fails midway, you can resume from the last known good state without re-deleting already removed teams.
For more advanced automation scenarios, you might look into integrating with other tools. For instance, if you are managing files associated with these projects, understanding how to automate file movements can streamline your cleanup process further. See
Automating Outlook File Movements for insights on handling associated data.
Frequently Asked Questions
Can I restore a deleted team?
Yes, but there is a limited recovery period. Deleted Microsoft 365 Groups enter a soft-deleted state for approximately 30 days. During this window, an administrator can restore the group using PowerShell or the Graph API. After 30 days, the data is permanently purged and cannot be recovered.
Why do I get a 403 error despite having permissions?
This usually happens because the app registration lacks admin consent. Even if you have assigned the
Group.ReadWrite.All role, it must be explicitly approved by a global administrator in the Azure Portal. Without this step, the token issued will not carry the necessary privileges for management actions.
Is it safe to delete teams while users are active?
Deleting a team removes access for all members immediately. Users will lose access to chats, files, and tabs. It is best practice to notify stakeholders before performing bulk deletions. Ensure that any critical data has been backed up or migrated to another location prior to execution.
How do I handle teams with custom applications installed?
Custom apps and extensions are automatically removed when the underlying group is deleted. However, if those apps store external data in separate databases, that data remains unaffected. You must manually clean up any external resources linked to the team to prevent orphaned records in your systems.
What is the difference between disabling and deleting a team?
Disabling a team restricts access but keeps the group and its data intact. Deleting removes the group entirely from the directory. Disabling is useful for temporary pauses, while deletion is permanent. Choose disabling if you suspect you might need the data again soon.