Grant admin consent with PowerShell:


Many articles and Azure module commands offer the option of performing admin consent on an application object. However, the Azure Portal also provides the same functionality for Service Principals.

In my specific situation, I have control over both the hosting tenant of the multi-tenant app registration. This allows me to utilize the “requiredResourceAccess” property to retrieve all OAuth2 permission grants and app role assignments from the source app registration. I can then reapply this information to the service principal in the consuming tenant.

This approach achieves a result similar to administering consent through the admin portal, but it doesn’t necessitate user interaction. It can be fully automated, making it ideal for scenarios where you need to add scopes or roles to an application without requiring manual reconsent in all managed tenants.

Here’s the code for admin consent with powershell:

# Source Tenant ID 
$STenantId = "xxx-xx-x-x-x-x"
#Target Tenant ID
$TTenantId = "xxx-x-x-x-x"
$SSpnId = "xx-x-x-x-x"
$SSpnAppId = "x-x-x-x-x"

# Calling all graph APIs
$spn = (New-GraphGetRequest -tenantid $TTenantId -uri "'$($SSpnAppId)')")
$oauth2Perms = (New-GraphGetRequest -tenantid $TTenantId -uri "'$($SSpnAppId)')/oauth2PermissionGrants")
$requiredResourceAccess = (New-GraphGetRequest -tenantid $STenantId -uri "$($SSpnId)").requiredResourceAccess
$spn = (New-GraphGetRequest -tenantid $TTenantId -uri "'$($SSpnAppId)')")
$appRoles = (New-GraphGetRequest -tenantid $TTenantId -uri "'$($SSpnAppId)')/appRoleAssignments")

foreach($resource in $requiredResourceAccess){
    $scopes = $Null; $scopes = $resource.resourceAccess | where{$_.type -eq "Scope"}
    $roles = $Null; $roles = $resource.resourceAccess | where{$_.type -eq "Role"}
    $targetSpn = (New-GraphGetRequest -tenantid $TTenantId -uri "'$($resource.resourceAppId)')")

        $scopeArray = $Null;
        foreach($scope in $scopes){
            $scopeArray += "$(($targetSpn.oauth2PermissionScopes | Where-Object {$ -eq $}).value) "

        $existingPermission = $oauth2Perms | Where-Object {$_.resourceId -eq $ -and $_.clientId -eq $}

        $body = @{
            "clientId"= $
            "consentType"= "AllPrincipals"
            "resourceId" = $
            "scope" = $scopeArray.Trim()

            $method = "PATCH"
            $uri = "$($"
            $method = "POST"
            $uri = ""

        New-GraphPOSTRequest -type $method -tenantid $TTenantId -uri $uri -body ($body | convertto-json -depth 15)

        foreach($role in $roles){
            $existingPermission = $Null; $existingPermission = $appRoles | Where-Object {$_.appRoleId -eq $ -and $_.principalId -eq $ -and $_.resourceId -eq $}
                $body = @{
                    "principalId" = $
                    "resourceId" = $
                    "appRoleId"= $                 
                New-GraphPOSTRequest -tenantid $TTenantId -uri "'$($resource.resourceAppId)')/appRoleAssignments" -body ($body | convertto-json -depth 15)    

To execute this, you need to have “DelegatedPermissionGrant.ReadWrite.All” and “AppRoleAssignment.ReadWrite.All” graph permissions for the calling principal, whether it’s a user or an application.

If you lack access to the source tenant (e.g., in a multi-tenant setup), you can alternatively create a hashtable containing the required permissions. These permissions can be defined manually or exported from the application manifest.

Leave a Reply

Your email address will not be published. Required fields are marked *