https://blog.nico-schiering.de/granting-azure-ad-admin-consent-programmatically/
https://samcogan.com/provide-admin-consent-fora-azure-ad-applications-programmatically/
Standing on the shoulders of giants here is a script that creates an Azure AD Application grants it access to the MS Graph API and the Mail.Send role ability.
It could be modified to grant access to different resources and permissions
Granting Admin Consent
There are two functions that can do an admin consent for Application Permissions
Grant-AdminConsentPermissionsToApp
Grant-OAuth2PermissionsToApp
The first function specifically approves the Application to use Microsoft Graph Mail.Send role with this function you would need to loop through each role to approve each one. The Grant-OAuth2PermissionsToApp function will approve multiple roles at once. I am using auth tokens taken from the context or Get-AzAccessToken check the code for specifics.
I logged in as a Global Administrator to run this script.
# run as admin
If (-NOT ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
$arguments = "& '" + $myinvocation.mycommand.definition + "'"
Start-Process powershell -Verb runAs -ArgumentList $arguments
Break
}
function logThis ($text, $logFile) {
"[$(Get-Date -format 'yyyy-MM-dd HH:mm:ss')] $($text)" | out-file $logFile -append
}
# place to save output
$tmpPath = "C:\Temp\Test"
$appName = "My Test App 6";
#Setup Logging
$logFile = "$($tmpPath)\AppInstallationLog.txt"
if (!(Test-Path "$($tmpPath)")) { New-Item -ItemType directory -path "$($tmpPath)" }
logThis "[INFO] ******************* SCRIPT START *******************" $logFile
$error.clear()
#Define Functions:
# working
<#
This function can approve an individual role
So in this case it is approving the application to access the Microsoft Graph API and specifically Mail.Send
This is NOT doing delegated approval but Application approval (you need this so that a program can send email as any user)
#>
Function Grant-AdminConsentPermissionsToApp {
$token = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com/").Token
$msGraphObjectId = (Get-AzureADServicePrincipal -All $true | Where-Object { $_.DisplayName -eq "Microsoft Graph" }).ObjectId
$apiUrl = "https://graph.microsoft.com/v1.0/servicePrincipals/$($msGraphObjectId)/appRoleAssignments"
# The Object ID of the service principal
$principalId = (Get-AzureADServicePrincipal -All $true | Where-Object { $_.AppId -eq $newAppId }).ObjectId
# Mail.Send Id
$appRoleId = ((Get-AzureADServicePrincipal -All $true | Where-Object { $_.DisplayName -eq "Microsoft Graph" }).AppRoles |
Where-Object { $_.Value -eq "Mail.Send" }).Id
$body = @{
principalId = $principalId
resourceId = $msGraphObjectId
appRoleId = $appRoleId
}
Invoke-RestMethod -Uri $apiUrl -Headers @{Authorization = "Bearer $($token)" } -Method POST -Body $($body | convertto-json) -ContentType "application/json"
}
Function Grant-OAuth2PermissionsToApp {
$context = Get-AzContext
if ($null -eq $context) {
$null = Connect-AZAccount -EA stop
$context = Get-AzContext
}
# get an access token to access resource https://main.iam.ad.ext.azure.com / 74658136-14ec-4630-ad9b-26e160ff0fc6
$token = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate($context.Account, $context.Environment, $context.Tenant.Id, $null, "Never", $null, "74658136-14ec-4630-ad9b-26e160ff0fc6")
$header = @{
'Authorization' = 'Bearer ' + $token.AccessToken
'X-Requested-With' = 'XMLHttpRequest'
'x-ms-client-request-id' = [guid]::NewGuid()
'x-ms-correlation-id' = [guid]::NewGuid()
}
$url = "https://main.iam.ad.ext.azure.com/api/RegisteredApplications/$newAppId/Consent?onBehalfOfAll=true"
Invoke-RestMethod -Uri $url -Headers $header -Method POST -ErrorAction Stop
}
if (Get-Module -ListAvailable -Name AzureAD)
{}
else {
Install-Module -Name AzureAD
logThis "[INFO] Installing Module AzureAD" $logFile
}
Write-Host "Please Log in with an Azure AD Admin Account"
Connect-AzureAD
Write-Host "Creating Application with Mail.Send Permissions within your Azure AD Tenant...Please wait..."
$tenant = Get-AzureADTenantDetail
# first get the MS Graph service principal
$msGraphPrincipal = Get-AzureADServicePrincipal -All $true | Where-Object { $_.DisplayName -eq "Microsoft Graph" }
$requiredResourceAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$requiredResourceAccess.ResourceAppId = $msGraphPrincipal.AppId
$msgraphRole = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "b633e1c5-b582-4048-a93e-9f11b44c7e96", "Role"
# Duplicate each role here you want to add here
#$msgraphRole2 = New-Object -TypeName "Microsoft.Open.AzureAD.Model.ResourceAccess" -ArgumentList "GUID of Role look in manifest in the portal to find this", "Role"
$requiredResourceAccess.ResourceAccess = $msgraphRole #, $msgraphRole2 pass each role you want to add on this line as an array
$newApp = New-AzureADApplication -DisplayName $appName -RequiredResourceAccess @($requiredResourceAccess)
logThis "[INFO] Application Created" $logFile
# password with 5 year expiry
$appSecret = New-AzureADApplicationPasswordCredential -ObjectId $newApp.ObjectId -CustomKeyIdentifier "$($appName) Key" -EndDate (get-date).AddYears(5)
logThis "[INFO] Secret Key Created" $logFile
# needed for granting admin consent
# create a service principal and associate it with the Azure Application
$svcPrincipal = New-AzureADServicePrincipal -AppId $newApp.AppId -Tags @("WindowsAzureActiveDirectoryIntegratedApp")
logThis "[INFO] Service Principal Created" $logFile
$newAppId = $newApp.AppId
$tenantId = $tenant.ObjectId
$appSecretValue = $appSecret.Value
$tenantDomain = ($tenant.VerifiedDomains | ? { $_._Default -eq $true }).Name
logThis "[INFO] Sleep Started" $logFile
Write-Host "Sleeping 30 seconds"
Start-Sleep -s 30
# this works to do app consent for individual roles but you would need to loop through each role to consent
# Grant-AdminConsentPermissionsToApp
logThis "[FUNCTIONCALL] Grant-OAuth2PermissionsToApp" $logFile
# this bulk approves all the roles
Grant-OAuth2PermissionsToApp
#Write-Out Access Details to Log File
logThis "Application Created Successfully" $logFile
logThis "Application (client) ID: " + $newAppId $logFile
logThis "Directory (tenant) ID: " + $tenantId $logFile
logThis "Client Key: " + $appSecretValue $logFile
logThis "Tenant Domain: " + $tenantDomain $logFile
#Error Collection
if ($error.count -gt 0) {
logThis "[WARN] Error Count: " + $error.count $logFile
logThis "[WARN] Error Text: " $logFile
logThis $error $logFile
logThis "*** End Error Text ***" $logFile
}
else
{ logThis "[INFO] No Errors" $logFile }
logThis "[INFO] ******************* SCRIPT END *******************" $logFile
Write-Host "Application successfully created..."
Write-Host " "
Write-Host "Application (client) ID:" $newAppId
Write-Host "Directory (tenant) ID:" $tenantId
Write-Host "Client Key:" $appSecretValue
Write-Host "Tenant Domain:" $tenantDomain
Write-Host " "
Write-Host "Please store the following file safely (i.e. encrypted somewhere):"
Write-Host "$($logFile)"
pause
Thank you so much! I don't even want to count the hours I spent trying to get this working via powershell. Really appreciate you working this our and writing it up!
You're most welcome.