Create and Configure Azure AD Application using PowerShell

In this article, we will explain how to create a new Azure AD application, configure API permissions, create an Enterprise Application (Service Principal) for the new app, and provide user and admin consent to the app using the PowerShell script. We will also demonstrate how to acquire an app access token by using the newly created application and access Microsoft Graph API resources.

If you are new to using Azure AD applications, then we would recommend reading this post to know more about how to register Azure AD application and how to configure permissions and provide consent to the app from the Azure AD portal.

Before you start, install the Azure AD V2 PowerShell module and run the following command to connect the module.

Connect-AzureAD

Summary

Create a new Azure AD Application using PowerShell

We can use the New-AzureADApplication cmdlet to create a new Azure Active Directory application. Run the following command to create a new app.

$aadApplication = New-AzureADApplication -DisplayName "MTS Demo App" -IdentifierUris "http://mtsdemoapp.contoso.com" -HomePage "http://mtsdemo.contoso.com"

You can view the newly created app in the App registrations blade, under All applications in the Azure portal. Run the following commands to add the current user as Owner of the new app, hence you will also see the app under Owned applications.

$currentUser = (Get-AzureADUser -ObjectId (Get-AzureADCurrentSessionInfo).Account.Id)
Add-AzureADApplicationOwner -ObjectId $aadApplication.ObjectId -RefObjectId $currentUser.ObjectId

Configure required API Permissions in Azure AD Application

In Azure AD Portal, we can select the required app in App registrations and assign the required permissions under the section Manage -> API permissions. First, we need to select the required resource API (Ex: Microsoft Graph) and choose the required permissions (Ex: User.Read.All, Reports.Read.All). The permission can either be Application permissions or Delegated permissions. Here, we are going to execute the same steps with the PowerShell script.

Run the following commands to configure the required Application and Delegated permissions in the newly created Azure AD application.

#Get Service Principal of Microsoft Graph Resource API 
$graphSP =  Get-AzureADServicePrincipal -All $true | Where-Object {$_.DisplayName -eq "Microsoft Graph"}

#Initialize RequiredResourceAccess for Microsoft Graph Resource API 
$requiredGraphAccess = New-Object Microsoft.Open.AzureAD.Model.RequiredResourceAccess
$requiredGraphAccess.ResourceAppId = $graphSP.AppId
$requiredGraphAccess.ResourceAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.ResourceAccess]

#Set Application Permissions
$ApplicationPermissions = @('User.Read.All','Reports.Read.All')

#Add app permissions
ForEach ($permission in $ApplicationPermissions) {
$reqPermission = $null
#Get required app permission
$reqPermission = $graphSP.AppRoles | Where-Object {$_.Value -eq $permission}
if($reqPermission)
{
$resourceAccess = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$resourceAccess.Type = "Role"
$resourceAccess.Id = $reqPermission.Id    
#Add required app permission
$requiredGraphAccess.ResourceAccess.Add($resourceAccess)
}
else
{
Write-Host "App permission $permission not found in the Graph Resource API" -ForegroundColor Red
}
}

#Set Delegated Permissions
$DelegatedPermissions = @('Directory.Read.All', 'Group.ReadWrite.All') #Leave it as empty array if not required

#Add delegated permissions
ForEach ($permission in $DelegatedPermissions) {
$reqPermission = $null
#Get required delegated permission
$reqPermission = $graphSP.Oauth2Permissions | Where-Object {$_.Value -eq $permission}
if($reqPermission)
{
$resourceAccess = New-Object Microsoft.Open.AzureAD.Model.ResourceAccess
$resourceAccess.Type = "Scope"
$resourceAccess.Id = $reqPermission.Id    
#Add required delegated permission
$requiredGraphAccess.ResourceAccess.Add($resourceAccess)
}
else
{
Write-Host "Delegated permission $permission not found in the Graph Resource API" -ForegroundColor Red
}
}

#Add required resource accesses
$requiredResourcesAccess = New-Object System.Collections.Generic.List[Microsoft.Open.AzureAD.Model.RequiredResourceAccess]
$requiredResourcesAccess.Add($requiredGraphAccess)

#Set permissions in existing Azure AD App
$appObjectId=$aadApplication.ObjectId
#$appObjectId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
Set-AzureADApplication -ObjectId $appObjectId -RequiredResourceAccess $requiredResourcesAccess

Note: The above script updates the permissions in the existing Azure AD application. You can also use the same script to set permissions while creating a new application.

New-AzureADApplication -DisplayName "Permission Test App" -IdentifierUris "http://ptdemoapp.contoso.com" -RequiredResourceAccess $requiredResourcesAccess

Create client secret or Application password

When you request a token from a client application, a secret key is required to prove the application identity. The client secret key can also be referred to as the application password. You can create multiple keys and specify the validity period for your key. The below command creates a client secret key that will expire in two years. You can also specify a StartDate if you do not want the key activated immediately.

$appObjectId=$aadApplication.ObjectId
#$appObjectId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$appPassword = New-AzureADApplicationPasswordCredential -ObjectId $appObjectId -CustomKeyIdentifier "AppAccessKey" -EndDate (Get-Date).AddYears(2)
$appPassword.Value #Display app secret key

Create new Service Principal or Enterprise Application for Azure AD Application

Once we created an Azure AD application, a service principal object (Enterprise application) is required for the application to access resources that are secured by Azure AD tenant. The security principal defines the access policy and permissions for the application in the Azure AD tenant. This enables core features such as authentication of the user/application during sign-in, and authorization during resource access.

Run the following commands to create a new service principal for the Azure AD application.

#Provide Application (client) Id
$appId=$aadApplication.AppId
#$appId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$servicePrincipal = New-AzureADServicePrincipal -AppId $appId -Tags @("WindowsAzureActiveDirectoryIntegratedApp")

When you register a new application from the App registrations blade in the Azure portal, a service principal object for the application will be automatically created in your tenant and it will be available under Enterprise applications blade in the portal. If you created the app as a multi-tenant app and want to use it in different tenants such as a customer tenant, the service principal object will be created in the customer tenant when the customer provides permission to access resources in their tenant (upon registration or user consent or admin consent). They can also use PowerShell, Azure CLI, and other tools to create this security principal.

The service principal object is the local representation or application instance of a global Azure AD application in a single tenant or directory. The service principal can also be called as Enterprise Application or Managed Application in the local directory. You can refer to this post to know more about service principal: Azure AD Application and Service principal object.

As we already explained, the service principal (aka Enterprise application) of the application will control the resource access for the application in the Azure AD tenant. To acquire an access token for the configured permissions, the required consent (admin or user consent) should already have been provided for the required permissions in the service principal object.

Here, we are explaining how to grant consent for Application and Delegated permissions using the PowerShell script. We can also provide admin consent through the Azure AD portal or with admin consent URL, you can refer to this post for more details: Grant tenant-wide admin consent to an application.

$requiredResourcesAccess – In the below scripts we have used the object $requiredResourcesAccess, you can refer to the above section Configure required API Permissions to form this object. If the Azure AD application available in your Tenant, then you can get the configured permissions by running the following commands.

$appObjectId=$aadApplication.ObjectId
#$appObjectId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$requiredResourcesAccess=(Get-AzureADApplication -ObjectId $appObjectId).RequiredResourceAccess

$servicePrincipal – In the below scripts we have used the object $servicePrincipal to get the Object Id of the service principal (Enterprise application). You can run the following commands to get the service principal object of your Azure AD application by providing the application’s AppId (Application client id).

#Provide Application (client) Id
$appId=$aadApplication.AppId
#$appId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
$servicePrincipal = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $appId}

Grant Admin consent for Application permissions

Run the following commands to grant admin consent for the application permissions that are configured in the app.

ForEach ($resourceAppAccess in $requiredResourcesAccess)
{
$resourceApp = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $resourceAppAccess.ResourceAppId}
ForEach ($permission in $resourceAppAccess.ResourceAccess)
{
if ($permission.Type -eq "Role")
{
New-AzureADServiceAppRoleAssignment -ObjectId $servicePrincipal.ObjectId -PrincipalId $servicePrincipal.ObjectId -ResourceId $resourceApp.ObjectId -Id $permission.Id
}
}
}

Grant User or Admin consent for Delegated permissions

We are going to use Microsoft Graph API to grant consent for the delegated permissions, so we need to get an access token with the required permissions to create or update a delegated permission grant (oAuth2PermissionGrant). 

$accessToken – Run the following commands to retrieve access token by using the AzureAD Powershell app which provides a token with the required privilege.

# Set ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory.dll) assembly path from Azure AD module location
$AADModule = Import-Module -Name AzureAD -ErrorAction Stop -PassThru
$adalPath = Join-Path $AADModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.dll"
$adalformPath = Join-Path $AADModule.ModuleBase "Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll"
[System.Reflection.Assembly]::LoadFrom($adalPath) | Out-Null
[System.Reflection.Assembly]::LoadFrom($adalformPath) | Out-Null  
     
# Azure AD PowerShell client id. 
$ClientId = "1950a258-227b-4e31-a9cf-717495945fc2"
$RedirectUri = "urn:ietf:wg:oauth:2.0:oob"
$resourceURI = "https://graph.microsoft.com"
$authority = "https://login.microsoftonline.com/common"
$authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority      

# Get token by prompting login window.
$platformParameters = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.PlatformParameters" -ArgumentList "Always"
$authResult = $authContext.AcquireTokenAsync($resourceURI, $ClientID, $RedirectUri, $platformParameters)
$accessToken = $authResult.Result.AccessToken

Run the following commands to grant consent for all the users or required users. By default, the script gives consent for all the users (admin consent), you can set the value for $GrantConsnetForAllUsers as $false and provide the required user id to give consent only for the required user (user consent).

#$requiredResourcesAccess - Refer Configure required API permissions section to form this detail or get it from Get-AzureADApplication for your app
#$servicePrincipal - The servicePrincipal (Enterprise application) object of your Azure AD application
#$accessToken - Require graph access token with required permissions to update oauth2PermissionGrants

$GrantConsnetForAllUsers=$true #Set $true to give consent for all users and set $false to give consent for individual user
if ($GrantConsnetForAllUsers) {
#Grant consent for all users
$consentType = "AllPrincipals"
$principalId = $null
} else {
#Grant consent for the required user alone
$consentType = "Principal"
#Get or provide object id for the required Azure AD user
$principalId = (Get-AzureADUser -SearchString "[email protected]").ObjectId
#$principalId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

ForEach ($resourceAppAccess in $requiredResourcesAccess)
{
$delegatedPermissions = @()
#$resourceApp - get servicePrincipal of Resource API App(ex: Microsoft Graph, Office 365 SharePoint Online)
$resourceApp = Get-AzureADServicePrincipal -All $true | Where-Object {$_.AppId -eq $resourceAppAccess.ResourceAppId}
ForEach ($permission in $resourceAppAccess.ResourceAccess)
{
if ($permission.Type -eq "Scope")
{
$permissionObj = $resourceApp.OAuth2Permissions | Where-Object {$_.Id -contains $permission.Id}
$delegatedPermissions += $permissionObj.Value
}
}

if($delegatedPermissions)
{
#Get existing grant entry
$existingGrant = Get-AzureADOAuth2PermissionGrant -All $true | Where { $_.ClientId -eq $servicePrincipal.ObjectId -and $_.ResourceId -eq $resourceApp.ObjectId -and  $_.PrincipalId -eq $principalId}

if(!$existingGrant){
#Create new grant entry
$postContent = @{
clientId = $servicePrincipal.ObjectId
consentType = $consentType
principalId = $principalId
resourceId  = $resourceApp.ObjectId
scope       = $delegatedPermissions -Join " "
}

$requestBody = $postContent | ConvertTo-Json
Write-Host "Grant consent for $delegatedPermissions ($($resourceApp.DisplayName))" -ForegroundColor Green
$headers = @{Authorization = "Bearer $accessToken"}
$response = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/oauth2PermissionGrants" -Body $requestBody -Method POST -Headers $headers -ContentType "application/json"

} else {
#Update existing grant entry
$delegatedPermissions+=$existingGrant.Scope -Split " "
$delegatedPermissions = $delegatedPermissions | Select -Unique
$patchContent = @{
scope       = $delegatedPermissions -Join " "
}

$requestBody = $patchContent | ConvertTo-Json
Write-Host "Update consent for $delegatedPermissions ($($resourceApp.DisplayName))" -ForegroundColor Green
$headers = @{Authorization = "Bearer $accessToken"}
$response = Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/oauth2PermissionGrants/$($existingGrant.ObjectId)" -Body $requestBody -Method PATCH -Headers $headers -ContentType "application/json"

}
}
}

Get access token on behalf of the app – Application permissions

Once you have successfully created and configured an Azure AD application, run the following commands to get a resource access token with configured Application permissions.

#Get or provide your Office 365 Tenant Id or Tenant Domain Name
$tenantId = (Get-AzureADTenantDetail).ObjectId
#$tenantId = "contoso.onmicrosoft.com"

#Provide Application (client) Id of your app
$appClientId=$aadApplication.AppId
#$appClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

#Provide Application client secret key
$clientSecret = $appPassword.Value
#$clientSecret ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

$requestBody = @{client_id=$appClientId;client_secret=$clientSecret;grant_type="client_credentials";scope="https://graph.microsoft.com/.default";}
$oauthResponse = Invoke-RestMethod -Method Post -Uri https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token -Body $requestBody
$accessToken = $oauthResponse.access_token

Get access token on behalf of a user – Delegated permissions

For Delegated permissions token, we would recommend you to use a sign-in library such as MSAL (or ADAL) and prompt the user to log-in. For unattended sign-in access (without login-prompt window), we can use OAuth 2.0 Resource Owner Password Credentials flow.

Run the following commands to get an access token on behalf of a user by sending the required username and plain password.

#Get or provide your Office 365 Tenant Id or Tenant Domain Name
$tenantId = (Get-AzureADTenantDetail).ObjectId
#$tenantId = "contoso.onmicrosoft.com"

#Provide Application (client) Id of your app
$appClientId=$aadApplication.AppId
#$appClientId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

#Provide Application client secret key
$clientSecret = $appPassword.Value
#$clientSecret ="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

$username= "[email protected]"
$password= "user_password"
$scope="Directory.Read.All openid profile offline_access"

$requestBody = @{client_id=$appClientId;client_secret=$clientSecret;grant_type="password";username=$username;password=$password;scope=$scope;}
$oauthResponse = Invoke-RestMethod -Method Post -Uri https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token -Body $requestBody
$accessToken = $oauthResponse.access_token

Use the access token to call Microsoft Graph

The below command calls the users endpoint in the Microsoft Graph API resource and retrieves Azure AD user details.

$apiUrl = "https://graph.microsoft.com/v1.0/users"
$users = Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} -Uri $apiUrl -Method Get

Advertisement