Hello Diptesh Kumar,
Welcome to the Microsoft Q&A and thank you for posting your questions here.
I understand that you would like to grant the "Manage Delivery Plans" permission across all projects in an Azure DevOps organization for only two specific groups by using PowerShell with Azure DevOps CLI or REST API or Direct REST API calls via scripting.
To grant the "Manage Delivery Plans" permission across all projects in an Azure DevOps organization for only two specific groups, you can use either:
- PowerShell with Azure DevOps CLI or REST API, or
- Direct REST API calls via scripting.
The steps below will guide you and it is PowerShell with Azure DevOps REST API:
- Prerequisites:
- Azure DevOps PAT (Personal Access Token) with Organization-level permissions.
- PowerShell installed.
- The two Azure DevOps group descriptors (not just names).
- Organization URL (e.g.,
https://dev.azure.com/your-org
).
- Based on the official Microsoft documentation - https://learn.microsoft.com/en-us/azure/devops/organizations/security/namespace-reference?view=azure-devops - the "Manage Delivery Plans" permission is part of the Delivery Plans security namespace, which is object-level and managed per plan or per project. However, the exact bitmask value for this permission is not explicitly documented. To retrieve the correct permission bitmask, you can use the Security Namespaces API:
This will return a list of permissions and their corresponding bitmask values for the Delivery Plans namespace.GET https://dev.azure.com/{organization}/_apis/securitynamespaces/33344d9c-fc72-4d6f-aba5-fa317101a7e9?api-version=7.1-preview.1
- PowerShell Script:
This script includes:# ============================ # Configuration # ============================ $organization = "DevOrgName" $pat = "PATForAzAdOps" # Replace with your actual PAT $groupNames = @("GP1name", "GP2Name") $securityNamespaceId = "33344d9c-fc72-4d6f-aba5-fa317101a7e9" # Base64-encoded PAT for authentication $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat")) # ============================ # Helper: Get Group Descriptor # ============================ function Get-GroupDescriptor { param ([string]$groupName) $url = "https://vssps.dev.azure.com/$organization/_apis/graph/groups?api-version=7.1-preview.1" $response = Invoke-RestMethod -Uri $url -Headers @{Authorization=("Basic $base64AuthInfo")} -Method Get $group = $response.value | Where-Object { $_.displayName -eq $groupName } if ($group) { return $group.descriptor } else { throw "Group '$groupName' not found." } } # ============================ # Step 1: Get All Projects # ============================ $projectsUrl = "https://dev.azure.com/$organization/_apis/projects?api-version=7.1-preview.4" try { $projects = Invoke-RestMethod -Uri $projectsUrl -Headers @{Authorization=("Basic $base64AuthInfo")} -Method Get } catch { Write-Error "Failed to retrieve projects: $_" exit } # ============================ # Step 2: Get Group Descriptors # ============================ $groupDescriptors = @{} foreach ($groupName in $groupNames) { try { $descriptor = Get-GroupDescriptor -groupName $groupName $groupDescriptors[$groupName] = $descriptor } catch { Write-Warning $_ } } # ============================ # Step 3: Apply Permissions # ============================ foreach ($project in $projects.value) { $projectId = $project.id $token = "vstfs:///Classification/TeamProject/$projectId" foreach ($groupName in $groupDescriptors.Keys) { $descriptor = $groupDescriptors[$groupName] $body = @{ accessControlEntries = @(@{ descriptor = $descriptor allow = 16 # Placeholder: Replace with actual bitmask after confirmation deny = 0 token = $token }) } | ConvertTo-Json -Depth 10 $url = "https://dev.azure.com/$organization/_apis/accesscontrolentries/$securityNamespaceId?api-version=7.1-preview.1" try { $response = Invoke-RestMethod -Uri $url -Headers @{ Authorization = "Basic $base64AuthInfo" "Content-Type" = "application/json" } -Method Post -Body $body Write-Host "Permission applied for '$groupName' on project '$($project.name)'" -ForegroundColor Green } catch { Write-Warning "Failed to apply permission for '$groupName' on project '$($project.name)': $_" } } }
- Bitmask retrieval placeholder
- Group descriptor resolution
- Eror handling
- Logging
- Idempotency check
- NOTICE: You have to change bitmask and the following $organization = "DevOrgName" $pat = "PATForAzAdOps" # Replace with your actual PAT $groupNames = @("GP1name", "GP2Name") Replace with actual Group name.
I hope this is helpful! Do not hesitate to let me know if you have any other questions or clarifications.
Please don't forget to close up the thread here by upvoting and accept it as an answer if it is helpful.