Reporting on multiple tenants with the Microsoft Graph

The aim of this project has been to show you how to manage multiple Microsoft 365 tenants quickly, easily and securely using the Microsoft Graph. this article builds on a previous article so go and take a look at:

Using the Microsoft Graph with multiple tenants

The complete steps in this whole process are:

1. Embed a ‘static’ Azure AD application in all the tenants you wish to access.

2. Give those ‘static’ Azure AD applications, in all those tenants, the appropriate permissions to access the tenant values.

3. Run a Graph request against these Azure AD applications in each tenant and extract the desired results.

This article will show you how to complete Steps 2 and 3. Step 1 was covered in the previous article.

Step 2 requires granting appropriate permissions to the Azure AD application already in place inside each tenant. The manual process of how to achieve this is covered in my article:

Using interactive PowerShell to access the Microsoft Graph

image

However, why do it manually if you can automate it I say? With that in mind, I have created a self executing PowerShell script to add the appropriate permissions to multiple tenants and allow the reading of OneDrive for Business usage information for all users. You’ll find the program to do this in my GitHub repo here:

https://github.com/directorcia/Office365/blob/master/graph-adapp-per-add.exe

You’ll need to download the file into the location where all the XML configuration files are that were created in Step 1. These will be needed again as the program cycles through all those tenants adding the appropriate permissions.

image

When you run the program, it will read the XML configuration files it finds in the directory and then ask you to login to each tenant again. You need to do this as you are granting/consenting to permissions and that requires administrator access.

image

You’ll need to complete the process of opening a browser session to each tenant and Accept the permissions as shown above. You’ll note that, in this case, they are read only permissions.

For more details on this process if you haven’t seen it, take a look at the article I wrote about doing the same thing for a single tenant:

Making PowerShell automation easier with the Microsoft Graph

Remember, that you don’t necessarily have to open the default browser all the time as the consent URL is always copied to the clipboard, so you could just past it into existing active sessions for that tenant if you wished.

image

The program will work through all the domains available.

image

If you want to see what’s happened visit the Azure portal for each tenant. Navigate to Azure Active Directory, then App Registrations, All Applications. Select the name of the Azure AD application you are using, then  API permissions as shown above. You should see that the only permission it has is Read All usage reports. You should not that consent has also been granted.

That now completes Step 2 of the process.

We now have an Azure AD application in all the desired tenants and that Azure AD application has the appropriate permissions to do things. We can now start extracting information by continuing to  Step 3.

image

In this example, we’ll run a program that will retrieve usage information about OneDrive for Business for each user in each tenant, without prompting for a login!

You’ll need to download the program I’ve written to do this (graph-odfb-get.exe), which you’ll find here:

https://github.com/directorcia/Office365/blob/master/graph-odfb-get.exe

Again, you need to place it the same directory where all the tenant configuration files are, as shown above, so it can access all the tenants configured in previous steps.

image

When you run the program, you’ll see the program loop through all the domains and all the users in those domains, without asking for a login.

image

At the end of each domain you’ll see a summary of OneDrive for Business for that domain as shown above.

image

At the end of the process you’ll see an aggregate summary for all your domains, as shown above.

This may seem like a lot of work but remember, you only need to do Steps 1 and 2 ONCE! Once the Azure AD application is configured for each tenant and the Graph has the appropriate permissions you can run Step 3 as MANY TIMES as you wish, securely, WITHOUT be prompted for a login to each tenant! How easy is that to automate?

This example has used just one aspect of the Graph being OneDrive for Business. You can use the Graph to do just about anything in Microsoft 365 you need to, including actually changing and update parameters!. In fact that is what I’m off to do right now.

Using the Microsoft Graph with multiple tenants

In a recent article:

Making PowerShell automation easier with the Microsoft Graph

I showed how to use the Microsoft Graph to embed an Azure AD application in a single tenant and then use that to make Graph queries against. What happens when you want to that across multiple tenants?

To achieve this you’ll need to basically do three things:

1. Embed a ‘static’ Azure AD application in all the tenants you wish to access.

2. Give those ‘static’ Azure AD applications, in all those tenants, the appropriate permissions to access the tenant values.

3. Run a Graph request against these Azure AD applications in each tenant and extract the results you want.

This article is going to look at Step 1 of this process.

So, the task at hand is to create a ‘static’ Azure AD application in all the tenants we want to access. I have detailed how to achieve this manually before here:

Using interactive PowerShell to access the Microsoft Graph

That may prove time consuming if you wish to do this across many tenants, so I have automated it via a freely available program here:

https://github.com/directorcia/Office365/blob/master/graph-adapp-add.exe

image

You can download the file into any directory on your machine. Best best is to use a Windows 10 machine that already has the AzureAD PowerShell module installed. This program will also generate a number of configuration files in the current directory for each domain you connect to.

image

Running the program will launch the PowerShell script as shown. You’ll then be prompted for the name of your Azure AD application. This is the display name that will appear inside your Azure AD. This name will be the same across all tenants you connect to. Here I’ve chosen to call my Azure AD application ciaops.

image

You’ll then be prompted for the email address of a tenant administrator with the rights to create an Azure AD application.

image

You’ll then be take through the normal sign in process for that tenant with that user as shown above. This will include any MFA if required.

image

The tenant will be check to see if an existing Azure AD application of the same name already exists and if it does you’ll see a warning like shown above. The program will then skip adding an Azure AD Application to this tenant and move on to the next tenant.

image

Assuming no Azure AD application of the same name exists in that tenant you’ll see that a new Azure AD application of that name is created. When a token is created in a tenant there are fours pieces of information that will need to be saved:

1. Application ID

2. Object ID

3. Application secret

4. Tenant ID

Each of these will be written to a secure configuration XML file I’ll explain in detail below. For now, just appreciate that these values need to be written securely to files so they can be used later. To achieve that, the program uses the get-credential PowerShell command to capture these securely to be written.

image

To complete this process all you need to do is use the Paste command (i.e. CTRL+V) when prompted at the password field as shown.

image

So here, simply hit CTRL+V and then ENTER. The actual value you are pasting is a few lines up in the display as you can see above if you need it.

image

You’ll need to complete that process four times for each variable as shown above.

You are then prompted for the next domain you wish to add an Azure AD application to. You repeat the same entry process for each new domain you wish to use.

image

When you have no more domains to configure, simply press Enter at the admin domain prompt. At that point, the program will disconnect from any Azure AD and use the captured credentials to check whether it can access all these tenants. To do this, it reads from the saved configuration files and makes a basic read request to the Microsoft Graph using the Azure AD application details for each tenant to verify success. It merely tests that it can get the Graph API for that tenant.

At this point you now have an Azure AD application of the same name, inside each tenant you configured, with no permissions to anything with the Graph.

image

If you now return to the directory where you ran the program from you’ll see a number of additional files as shown above.

The graph-adapp-set.txt is a log of the whole process so you can see what has happened.

You’ll also see four XML files per tenant. These contain the important variables for the tenant mentioned previously. They are in format of:

<domain>-tenid.xml – holds encrypted Tenant ID

<domain>-appsec.xml – holds the encrypted application secret of the Azure AD application for the tenant

<domain>.objid.xml – holds the encrypted Object ID of the Azure AD application for the tenant

<domain>.appid.xml – holds the encrypted Application ID of the Azure AD application for the tenant

Storing these details on a workstation is not the most secure option I agree, but it’s a starting point for what I’ll show you down track (read Azure Key Vault). However, because some people want the flexibility and simplicity of local files that’s where this starts.

image

If you examine one of these XML configuration files more closely, as shown above, you’ll see that the variable name (here AppSec) is stored in the Username field and the Password field has a long string of characters. You’ll notice that these characters actually don’t in anyway match the actual Appsec value that was captured earlier. That value was:

SNAGHTML10314b8e

This means that the actual tenant variables save in the files are encrypted, so they can’t be easily recovered.

image

To get the unencrypted values back you’ll need to use the PowerShell import-clixml as shown above.

image

Well, you maybe thinking that it is easy enough to copy these configuration files to another PC and decrypt them there. Not so fast my sneaky friend, because the way these details are encrypted is that they are locked to just THAT machine and just THAT logged in user! As you can see from the above, if you try and decrypt these files with another user on that same PC or on another machine, you can’t.

All of this comes about because of the use of the export-climxl command to save the variables, which says:

The Export-Clixml cmdlet encrypts credential objects by using the Windows Data Protection API. The encryption ensures that only your user account on only that computer can decrypt the contents of the credential object. The exported CLIXML file can’t be used on a different computer or by a different user.

That’s why you needed to do that CTL+V paste command for each variable previously so that the variable could be saved as a credential object and take advantage of this encryption process.

This has now achieved STEP 1 in the process I spoke about initially to allow secure access to multiple tenant using the Microsoft Graph.

image

So what does the program actually do to each tenant behind the scenes? It is easy to see. Simply visit the Azure AD Directory location in the Azure portal for that tenant. If you then select the App registration from the menu on the left, and ensure you are viewing All Applications, you should see the application with the name you entered displayed on the right as shown above. Here, ciaops.

image

If you select the application name to get more details you’ll many of the variables saved to XML files as shown above.

image

If you then select API permissions on the left you will see that, as yet, no permissions have been given to this Azure AD Application (although they will be in an upcoming article).

However, we are not quite done yet as I have also created a program that will remove all of these Azure AD applications created quickly and easily. To do that download the program:

 https://github.com/directorcia/Office365/blob/master/graph-adapp-del.exe

image

You need to place it into the directory where all the tenant configuration file are located as shown. Double click the program to run.

image

To remove that Azure AD application you’ll need to log back into every tenant interactively as shown above. You’ll see the same of the tenant that it wants credentials for in the program flow.

image

Once you have provided access to the tenant, the Azure AD application will be deleted along with the configuration files. You’ll then be take to the next tenant and asked to repeat the process.

image

Once there are no more configuration files found the program will end.

Remember, this program will delete every matching tenant it finds configuration files for in the current directory. If you only want to delete a subset of the total tenants you have configured, move the other configuration files out of the current directory until this process is complete.

In summary then, the programs that I have created and made available for free will create a ‘static’ Azure AD application in all the tenants you select. The idea in upcoming articles will be to show you how this ‘static’ embedded Azure AD application can now be used to report and potentially change the configuration of multiple tenants quickly and easily. I also provided a program to also remove all these Azure AD applications from tenants.

Next step will be to give the Azure AD applications appropriate permissions and then get some information from the tenants WITHOUT the need of manually logging into each.