Automating Azure AD

In the previous article, we explored how to interact (read / write) to an Azure AD tenant using Microsoft Graph API.

In the article before that, we looked at how to authenticate a user without using Azure AD web flow.

Those were motivated by a specific scenario:  replacing a LDAP server by Azure AD while migrating a SaaS application to Azure.

Now a SaaS application will typically have multiple tenants or instances.  Configuring Azure AD by hand, like any other Azure service, can be tedious and error prone.  Furthermore, once we’ve onboarded say 20 tenants, making a configuration change will be even more tedious and error prone.

This is why we’ll look at automation in this article.

We’ll look at how to automate the creation of Azure AD applications we used in the last two articles.  From there it’s pretty easy to generalize (aka exercise to the reader!).

Azure AD Tenant creation

From the get go, bad news, we can’t create the tenant by automation.

No API is exposed for that, we need to go through the portal.


Which PowerShell commands to use?

Automating Azure AD is a little confusing.  Too many options is like not enough.

The first approach should probably be to use the Azure PowerShell package like the rest of Azure services.  For instance, to create an application, we would use New-AzureRmADApplication.

The problem with that package for our scenario is that the Azure AD tenant isn’t attached to a subscription. This is typical for a SaaS model:  we have an Azure AD tenant to manage internal users on all subscriptions and then different tenants to manage external users.  Unfortunately, at the time of this writing, the Azure PowerShell package is tied around the Add-AzureRmAccount command to authenticate the user ; that command binds a subscription (or via the Select-AzureRmSubscription).  But in our case we do not have a subscription:  our Azure AD tenant isn’t managing a subscription.

The second approach would then be to use the MSOnline Module.  That’s centered around Azure AD, but it is slowly being deprecated for…

The third approach, Azure Active Directory V2 PowerShell module.  This is what we’re going to use.

I want to give a big shout to Chris Dituri for tapping the trail here.  His article Azure Active Directory: Creating Applications and SPNs with Powershell was instrumental to write this article.  As we’ll see, there are bunch of intricacies about the application permissions that aren’t documented and that Chris unraveled.

The first thing we’ll need to do is to install the PowerShell package.  Easy:

Install-Module AzureADPreview

If you read this from the future, this might have changed, so check out the documentation page for install instructions.


We need to connect to our tenant:

connect-azuread -TenantId bc7d0032

You can see the documentation on the Connect-AzureAD command here.

Where do we take our tenant ID?


Now we can go and create applications.


Here we’ll replicate the applications we built by hand in the Authenticating to Azure AD non-interactively article.

Remember, those are two applications, a service and a client one.  The client one has permission to access the service one & let users sign in to it.  As we’ll see, giving those permissions are a little tricky.

Let’s start by the final PowerShell code:

#  Grab the Azure AD Service principal
$aad = (Get-AzureADServicePrincipal | `
    where {$_.ServicePrincipalNames.Contains("")})[0]
#  Grab the User.Read permission
$userRead = $aad.Oauth2Permissions | ? {$_.Value -eq "User.Read"}

#  Resource Access User.Read + Sign in
$readUserAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
  ResourceAppId=$aad.AppId ;
    Id = $userRead.Id ;
    Type = "Scope"}}

#  Create Service App
$svc = New-AzureADApplication -DisplayName "MyLegacyService" `
    -IdentifierUris "uri://"
# Associate a Service Principal to the service Application 
$spSvc = New-AzureADServicePrincipal -AppId $svc.AppId
#  Grab the user-impersonation permission
$svcUserImpersonation = $spSvc.Oauth2Permissions | `
    ?{$_.Value -eq "user_impersonation"}
#  Resource Access 'Access' a service
$accessAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
  ResourceAppId=$svc.AppId ;
    Id = $svcUserImpersonation.Id ;
    Type = "Scope"}}
#  Create Required Access 
$client = New-AzureADApplication -DisplayName "MyLegacyClient" `
  -PublicClient $true `
  -RequiredResourceAccess $readUserAccess, $accessAccess

As promised, there is ample amount of ceremony.  Let’s go through it.

Grant Permissions

If we try to run the authentication piece of code we had in the article, we’ll first need to change the “clientID” value for $client.AppId (and make sure serviceUri has the value of “uri://”).

Now if we run that, we’ll get an error along the line of

The user or administrator has not consented to use the application with ID ‘…’. Send an interactive authorization request for this user and resource.

What is that?

There is one manual step we have to take, that is to grant the permissions to the application.  In Azure AD, this must be performed by an admin and there are no API exposed for it.

We could sort of automate it with code via an authentication workflow (which is what the error message is suggesting to do), which I won’t do here.

Basically, an administrator (of the Azure AD tenant) needs to approve the use of the app.

We can also do it, still manually, via the portal as we did in the article.  But first, let’s throw the following command:


On an empty tenant, there should be nothing returned.  Unfortunately, there are no Add/New-AzureADOAuth2PermissionGrant at the time of this writing (this might have changed if you are from the future so make sure you check out the available commands).

So the manual step is, in the portal, to go in the MyLegacyClient App, select Required Permissions then click the Grant Permissions button.


Once we’ve done this we can run the same PowerShell command, i.e.


and have two entries now.


We see the two permissions we attached to MyLegacyClient.

We should now be able to run the authentication code.

Graph API App

Here we’ll replicate the application we created by hand in the Using Microsoft Graph API to interact with Azure AD article.

This is going to be quite similar, except we’re going to attach a client secret on the application so that we can authenticate against it.

#  Grab the Azure AD Service principal
$aad = (Get-AzureADServicePrincipal | `
    where {$_.ServicePrincipalNames.Contains("")})[0]
#  Grab the User.Read permission
$userRead = $aad.Oauth2Permissions | ? {$_.Value -eq "User.Read"}
#  Grab the Directory.ReadWrite.All permission
$directoryWrite = $aad.Oauth2Permissions | `
  ? {$_.Value -eq "Directory.ReadWrite.All"}

#  Resource Access User.Read + Sign in & Directory.ReadWrite.All
$readWriteAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
  ResourceAppId=$aad.AppId ;
    Id = $userRead.Id ;
    Type = "Scope"}, [Microsoft.Open.AzureAD.Model.ResourceAccess]@{
    Id = $directoryWrite.Id ;
    Type = "Role"}}

#  Create querying App
$queryApp = New-AzureADApplication -DisplayName "QueryingApp" `
    -IdentifierUris "uri://" `
    -RequiredResourceAccess $readWriteAccess

#  Associate a Service Principal so it can login
$spQuery = New-AzureADServicePrincipal -AppId $queryApp.AppId

#  Create a key credential for the app valid from now
#  (-1 day, to accomodate client / service time difference)
#  till three months from now
$startDate = (Get-Date).AddDays(-1)
$endDate = $startDate.AddMonths(3)

$pwd = New-AzureADApplicationPasswordCredential -ObjectId $queryApp.ObjectId `
  -StartDate $startDate -EndDate $endDate `
  -CustomKeyIdentifier "MyCredentials"

You need to “grant permissions” for the new application before trying to authenticate against it.

Two big remarks on tiny bugs ; they might be fixed by the time you read this and they aren’t critical as they both have easy work around:

  1. The last command in the script, i.e. the password section, will fail with a “stream property was found in a JSON Light request payload. Stream properties are only supported in responses” if you execute the entire script in one go.  If you execute it separately, it doesn’t.  Beat me.
  2. This one took me 3 hours to realize, so use my wisdom:  DO NOT TRY TO AUTHENTICATE THE APP BEFORE GRANTING PERMISSIONS.  There seems to be some caching on the authentication service so if you do try to authenticate when you don’t have the permissions, you’ll keep receiving the same claims after even if you did grant the permissions.  Annoying, but easy to avoid once you know it.

An interesting aspect of the automation is that we have a much more fine grained control on the duration of the password than in the Portal (1 year, 2 years, infinite).  That allows us to implement a more aggressive rotation of secrets.


Automation with Azure AD, as with other services, helps reduce the effort to provision and the human errors.

There are two big manual steps that can’t be automated in Azure AD:

That might change in the future, but for now, that limits the amount of automation you can do with human interactions.

10 responses

  1. Vijay Gade 2017-08-01 at 16:12

    Can we have web App/API application with “Microsoft Active directory app and Power BI service”? what needs to modify in the script please suggest me, thanks.

  2. Vincent-Philippe Lauzon 2017-08-01 at 16:30

    Hi Vijay,

    I’m not sure I understand what you’re trying to do. Power BI Service is integrated with AAD by default…

  3. Anonymous 2017-08-03 at 11:02

    Hi vincent, i am trying to execute 2nd script in azure portal through ARM template getting an below issue, could you please look at that and suggest me, thanks.

    connect-azuread -TenantId $TenantId\n+ ~~~~~~~~~~~~~~~\n + CategoryInfo : ObjectNotFound: (connect-azuread:String) [], Com \n mandNotFoundException\n + FullyQualifiedErrorId : CommandNotFoundException\n \nGet-AzureADServicePrincipal : The term ‘Get-AzureADServicePrincipal’ is not \nrecognized as the name of a cmdlet, function, script file, or operable \nprogram. Check the spelling of the name, or if a path was included, verify \nthat the path is correct and try again.\nAt C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.9\Downloads\0\\nPowerbi_App.ps1:17 char:9\n+ $aad = (Get-AzureADServicePrincipal `\n+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n + CategoryInfo : ObjectNotFound: (Get-AzureADServicePrincipal:Str \n ing) [], CommandNotFoundException\n + FullyQualifiedErrorId : CommandNotFoundException\n \nUnable to find type [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]. \nMake sure that the assembly that contains this type is loaded.\nAt C:\Packages\Plugins\Microsoft.Compute.CustomScriptExtension\1.9\Downloads\0\\nPowerbi_App.ps1:37 char:1\n+ $readWriteAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{\n+
  4. Anonymous 2017-08-03 at 11:05

    Actually, i want add application in Azure AD with 2 API’s , 1. Microsoft.Azure.ActiveDirectory, 2. Power BI Service.

  5. Anonymous 2017-08-03 at 19:19

    I have ran both the scripts, one is create Native app and another one is created Web App, may i know the specific part of script executes either it needs to create app type “native or web app”

  6. Vincent-Philippe Lauzon 2017-08-30 at 14:03

    For API, always choose Web App.

  7. Mavi 2017-10-02 at 12:37

    Hi, I’ve a problem about the permissions. How could I add permission app1 to app2 while app1 and app2 are in different azure active directories? Thanks.

  8. Vincent-Philippe Lauzon 2017-10-03 at 08:52

    Do you mean you want to use app1 as a Service Principal and then use it to access app2?

    If so… I don’t think that is possible.

    Can you elaborate on the scenario that brings you there?

  9. Mavi 2017-10-03 at 11:06

    Thanks for replying! So I have two tenant, app1 in tenant1 and api2 in tenant2 (t1 and t2 are in different subscriptions). what I want to do is both users from t1 and t2 can access the api2. I’ve registered api2 as a service principal and added consent in the url, while I cannot find service principal of api2 in the required permission in app1. Do you have any suggestions? (thanks I know it’s kind of confusing…

  10. Vincent-Philippe Lauzon 2017-10-03 at 11:56

    Hi Mavi,

    AAD tenants do not belong to subscriptions like other Azure resources. So they aren’t limited to a subscription (see If that helps…

    Otherwise, the way to that would be to bring the users in a tenant, using AAD B2B (see

    But in general, ask yourself why you have two tenants. It usually result in a mess. User identity is key within an application and you shouldn’t spread it around multiple tenants unless they are from different organisations, in which case you can integrate with B2B.

Leave a comment