AzureAD/Applications/Grant-CKPermissions.ps1

function Grant-CKPermissions {
  <#
  .SYNOPSIS
  Grant permissions (Delegated or Application) to an Azure AD application (Service Principal).
   
  Author: Roberto Rodriguez (@Cyb3rWard0g)
  License: MIT
  Required Dependencies: None
  Optional Dependencies: None
   
  .DESCRIPTION
  Grant-CKPermissions is a simple PowerShell wrapper to grant permissions (Delegated or Application) to an Azure AD application (Service Principal).
 
  .PARAMETER spObjectId
  The object id (id) of the service principal want to grant permissions to.
 
  .PARAMETER resourceName
  Name of the resource we want to grant permissions from. This is the service principal name associated with the resource (i.e. Microsoft Graph).
 
  .PARAMETER permissionType
  Type of permissions to grant. It could of type Delegated or Application.
 
  .PARAMETER permissions
  An array of permissions to grant.
 
  .PARAMETER accessToken
  Access token used to access the API.
 
  .LINK
  https://docs.microsoft.com/en-us/graph/api/application-update?view=graph-rest-1.0&tabs=http
 
  .EXAMPLE
  Grant-CKPermissions -spObjectId 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' -resourceName 'Microsoft Graph' -permissionType Application -permissions @('Application.Read.All','Mail.Read') -accessToken $accessToken
 
  @odata.context : https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')/appRoleAssignments/$entity
  @odata.id : https://graph.microsoft.com/v2/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/directoryObjects/$/Microsoft.DirectoryServices.ServicePrincipal('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')/appRoleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  id : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  deletedDateTime :
  appRoleId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  createdDateTime : 2021-09-09T05:56:54.0044123Z
  principalDisplayName : CloudKatanaTest
  principalId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  principalType : ServicePrincipal
  resourceDisplayName : Microsoft Graph
  resourceId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 
  @odata.context : https://graph.microsoft.com/v1.0/$metadata#servicePrincipals('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')/appRoleAssignments/$entity
  @odata.id : https://graph.microsoft.com/v2/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/directoryObjects/$/Microsoft.DirectoryServices.ServicePrincipal('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx')/appRoleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  id : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  deletedDateTime :
  appRoleId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  createdDateTime : 2021-09-09T05:56:54.3879907Z
  principalDisplayName : CloudKatanaTest
  principalId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  principalType : ServicePrincipal
  resourceDisplayName : Microsoft Graph
  resourceId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
 
  .EXAMPLE
  Grant-CKPermissions -spObjectId 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' -resourceName 'Microsoft Graph' -permissionType Delegated -permissions @('Application.Read.All','Mail.Read') -accessToken $accessToken
 
  @odata.context : https://graph.microsoft.com/v1.0/$metadata#oauth2PermissionGrants/$entity
  @odata.id : https://graph.microsoft.com/v2/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/oauth2PermissionGrants/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  clientId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  consentType : AllPrincipals
  id : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  principalId :
  resourceId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  scope : Application.Read.All Mail.Read
  #>


  [cmdletbinding()]
  Param(
    [parameter(Mandatory = $true)]
    [String]$spObjectId,

    [Parameter(Mandatory=$true)]
    [string]$resourceName,

    [Parameter(Mandatory=$true)]
    [ValidateSet("Delegated","Application")]
    [string]$permissionType,

    [Parameter(Mandatory=$true)]
    [array]$permissions,

    [parameter(Mandatory = $true)]
    [String]$accessToken
  )

  # Get the service principal of resource we want to grant permissions from (i.e. Microsoft Graph)
  $resourceSP =  Get-CKAzADServicePrincipals -Filter "displayName eq '$resourceName'" -AccessToken $accessToken
  if (!$resourceSP) {
    Write-Error "No service principal was found with displayName '$($resourceName)'"
  }
  $resourceSPId = $resourceSP.id
  
  if ($permissionType -eq 'Application') {
    # Retrieve Role Assignments and create 'Resource Access Items'
    $ResourceAccessItems = @()
    Foreach ($p in $permissions) {
      $RoleAssignment = $resourceSP.appRoles | Where-Object { $_.Value -eq $p }
      $ResourceAccessItem = [PSCustomObject]@{
        "principalId" = $spObjectId
        "resourceId"  = $resourceSPId
        "appRoleId"   = $RoleAssignment.id
      }
      $ResourceAccessItems += $ResourceAccessItem
    }
    $RoleResults = @()
    foreach ($role in $ResourceAccessItems) {
      $resourceString = "servicePrincipals/$spObjectId/appRoleAssignments"
      $parameters = @{
        Resource = $resourceString
        HttpMethod = "Post"
        Body = $role
        AccessToken = $accessToken
      }
      $RoleResults += Invoke-CKMSGraphAPI @parameters
    }
    $RoleResults
  }
  else {
    # Check existing OAuth grants
    $allGrants = Get-CKOauth2PermissionGrants -AccessToken $accessToken
    $existingGrant = $allGrants | Where-Object { $_.clientId -eq $spObjectId }

    if ($existingGrant) {
      $permissionsGrantId = $existingGrant.id
      $permissionsArgument = $permissions -join ' '
      $permissionsStrings = @($permissionsArgument, $existingGrant.scope) -join ' '
      $permissions = $permissionsStrings.split(' ')

      $body = @{
        scope = "$permissions"
      }
      $resourceString = "oauth2PermissionGrants/$permissionsGrantId"
      $parameters = @{
        Resource = $resourceString
        HttpMethod = "Patch"
        Body = $body
        AccessToken = $accessToken
      }
    }
    else {
      $body = @{
        clientId = $spObjectId
        consentType = "AllPrincipals"
        principalId = $null
        resourceId = $resourceSPId
        scope = "$permissions"
        startTime = "$((get-date).ToString("yyyy-MM-ddTHH:mm:ss:ffZ"))"
        expiryTime = "$((get-date).AddYears(1).ToString("yyyy-MM-ddTHH:mm:ss:ffZ"))"
      }
      $parameters = @{
        Resource = "oauth2PermissionGrants"
        HttpMethod = "Post"
        Body = $body
        AccessToken = $accessToken
      }
    }
    # Grant delegated permissions
    $response = Invoke-CKMSGraphAPI @parameters
    $response
  }
}