Access the Microsoft Graph with a script

In a recent article I showed how to connect to the Microsoft Graph in a web browser:

Using the Microsoft Graph Explorer

I also showed how you could do the same:

Using Interactive PowerShell

This article is going to focus on how you can do the same thing but directly via a script that won’t prompt you for credentials.

Before running this script you’ll need to follow the Using Interactive PowerShell article and set up an app in your Azure AD.



During that process you’ll need to record three things that will be used here:

1. Application ID

2. Tenant ID

3. Client secret

I borrowed the connection piece of this script from:

which I found really handy in helping me understand all this. You can download my script from my GitHub repository here:

You’ll need to enter your own Application ID, Tenant ID and Client secret in the variables section. After that, all you need to do is run the script. The results for the query of /security/alerts will end up in a variable called $query which you can view. The actual content of the alerts you’ll find in $query.content.


This Graph connection script should now allow you to connect to the Microsoft Graph for a tenant and start running queries and returning values for entries in there. At the moment it only queries security alerts, but you can modify it to query anything in the Graph for your tenant.

Using interactive PowerShell to access the Microsoft Graph

I recently published an article on how you can browse the Microsoft Graph directly from a web page here:

using the Microsoft Graph Explorer

The next step is to start working with the Microsoft Graph using PowerShell.

This article was recently published by Microsoft:

IT Pros can now easily connect to Microsoft Graph Security with the PowerShell Module!

and one of the confusing things I found where it talks about “Registering your application”, which you need to do successfully before you can run all the PowerShell commands.

Now if I find that confusing I’m sure others will also, as there is a bit of trick in setting it up correctly. So here is what you need to do, step by step, to actually get it all working.


Login to using you Microsoft 365 credentials. Navigate to Azure Active Directory from the list of items on the left.


From the options available on the left select App registration (Preview).


From the pane on the right select New registration at the top of the page.


Give the new application a name. Here I have called it Graph. Next hit the Register button at the bottom.


You should now see the Overview of the app. On the right hand side save both the Application (client) ID and Directory (tenant) ID as you will need these later.


Here’s the bit that isn’t that clear in the existing documentation. Select the Authentication option from the menu and then on the right check the option


From what I can work out, normally apps need to return to a location after using Azure AD authentication. However, because we will be using an interactive PowerShell session, the selected option will simply return there. Again, not really clear in the documentation I read.

You don’t need to make any other changes on the page but ensure you now select Save in the top left.


Next, select the Certificates and secrets option on the left. On the pane that appears on the right select + New client secret.


Give the secret a name and an expiry period and select Add.


You should then see you new secret and the actual value of that secret to the right as shown above. You will need to copy this secret value and keep it secure. treat it like a password.

You will see a banner across the top of the pane telling you that this is only time you get to see the value of the secret in the clear. After you navigate away, you’ll no longer be able to simply copy and paste the complete entry, so do it now and save the secret somewhere secure as you will need it down the track.


Now select API permissions on the left. You should see text Microsoft Graph is hyperlinked, so select this. This means your app already has some basic access to the Microsoft Graph, here just user read right. If the Microsoft Graph entry isn’t visible for some reason you can select the + Add a permission button at the top and then select Microsoft Graph from the following page. Hopefully however, the Microsoft Graph hyperlink will already be there.


There are two boxes at the top of the page. Ensure the left hand (Delegated permissions) one is selected first.


Scroll through the list of permissions in the bottom section until you find the heading SecurityEvents and expand it as shown.


Select both options as shown:



Once these options have been select, press the Update permissions at the bottom of the page.


You’ll be returned to the permission summary page as shown. You should now see the additional permissions you added displayed. You will however note a warning icon next to them as well as a banner across the top informing you that you need to consent to these. We’ll do that shortly, however we want to add some more permissions, so again select the hyperlinked text Microsoft Graph.


This time ensure the box on the right (Application permissions) is selected.

In essence, think of the box on the left (Delegated permissions) as permission for interactive sessions like typing commands into the PowerShell manually. that requires a user to login each time. The right box (Application permissions) however, is going to allow operations without the need for an interactive user login. Thus, we can run a PowerShell script and not be prompted for login. thus, while we are in here it is a good idea to set up both sets of permissions to give you the flexibility later.


As before, scroll through the list of permissions below. Locate the SecurityEvents heading, expand this and select:



Once selected, press the Update permissions button at the bottom of the page to save the changes.


You are again returned to the summary page where you should see all the permissions added. You should see permissions of type Delegated and Application for the security events. A set for each.


If you scroll to the bottom of the page you should see a Grant consent section as shown. Select the Grant admin consent for tenant button below. This means all users will have the permissions you just created. If you don’t do this, then they will have to consent the first time they access the Microsoft Graph using this method.


You should see the above prompt asking you to confirm that you will be consenting for all users in the tenant. Select Yes to continue.


In a few moments, your permission screen should show all green as shown above.


As a final check in the portal, select the Owners option on the left and ensure the appropriate users are listed here. These people will basically have the permissions to edit the application settings, like what has just been configured.

Now you can run an elevated PowerShell window and type:

install-module microsoftgraphsecurity

Once that has installed successfully you can run:



Because this is an interactive PowerShell session you’ll need to login to the tenant. A login prompt will appear as shown, however be careful here. You enter your user login AND the Application ID from the app just created in the Azure AD portal here. That is the really long string of digits in the Overview part of the application you just added in Azure AD NOT the user password!


You’ll then be prompted for the user password and MFA if configured


If all of that is good then you should get results as shown above. Now you can continue on with your interactive PowerShell session and all the great stuff in the microsoftgraphsecurity module. Yeah!

The main trick is selecting the urn:ietf:wg:oauth:2.0:oob option as the Redirect URI when configuring the app.

You may have noticed that we have used the Application ID here but not the Application secret. That is because this is an interactive session where the user is required to login in first. if we don’t want to be prompted for a login we need to use the Application secret. That process will be covered in an up coming article so stay tuned.

Reporting mailbox logins

Before much of what is covered here is possible you need to ensure you have enabled all the logging in your Office 365 tenant. I’ve covered how to do that here:

Enabling Office 365 mailbox auditing

Enable mailbox auditing in Exchange Online

Enable activity auditing in Office 365

Once you have done that you will be able to track what’s going on in your tenant much better.

In the situation of a compromised mailbox, a bad actor has control of it using legitimate credentials. This eliminates looking for failed logins, because there won’t be any. It also makes the finding the bad actor tougher because their access is most likely mixed in with the legitimate user.

The place to start is to run an audit log search as I have detailed here:

Searching the Office 365 activity log for failed logins


However, as I mentioned, we can no longer search for failed logins, we need to use a different search criteria. I would suggest that you instead run a search using the attribute “User signed in to mailbox” as shown above. That will produce something like shown for all users. Problem with this is that times and dates are in UTC not local time and it is cumbersome to manipulate in a web page. You can of course manipulate by exporting the results to a spreadsheet for more control.


Unsurprisingly, I feel PowerShell offers a much better solution to check the logs and report as you can see above. The script to do this I have made freely available at my Github repo here:

Basically, it will search the Audit log for Exchange Items that are Mailbox logins and send that output to a nice table via the Out-Grid command. As you can see, using Out-Grid you can now easily sort by time by clicking the column heading, and thanks to the script, the times are local not UTC!

By default, the script will check the last 48 hours but you can easily modify that to suit your needs by either entering the scope in hours or entering a start and end date in the variables at the top of the script.

With this output I can now look for suspect IPs that login into the mailbox and begin hunting from there. However, remember, all of this relies on you enable your auditing BEFORE you need it. So, if you haven’t enabled it, go do it now! You’ll find scripts to enable the logs also in my Office 365 repo here:

Updated script to now check for Sweep


The bad actors out there are clever and they’ll use any means at their disposal. Normally, when a user is successfully phished the first thing bad actors do is manipulate the email handling rules of the mailbox to hide their activity.

Unfortunately, there are quite a lot of different ways to forward email in Office 365 including via the mailbox and via Outlook client rules. It was brought to my attention that there is in fact another way that forwarding can be done, using the Sweep function. You can read more about this ability at:

Organize your inbox with Archive, Sweep and other tools in

Sweep rules only run once a day but do provide a potential way for bad actors to hide their activity, however as it turned out Sweep was in fact being exploited by bad actors inside a compromised mailbox.

I have therefore updated my publicly available PowerShell script at:

That will now also check and report on any Sweep rules in finds in mailboxes as well as any other forwards configured in the tenant.

Let me know if you find any other methods that this doesn’t cover and I’ll look at incorporating those as well.

Using PowerShell to download all my Office 365 scripts together

I really like GitHub but the problem is that it is really a developer not IT Pro style environment. That means there is no easy way (that I know of at least) to simply to copy every file in a repository to a directory on your local computer. Yes, you can do that with Visual Code like I do, but what if you just want a complete copy so you can run the scripts that I have created quickly and easily?

Have no fear, PowerShell to the rescue once again.

I have just created the following script:

which, when run, will basically grab every file in my Office 365 repository and download it to the directory you nominate in the variable at the top of the script.


So the process is to copy the above script into the PowerShell ISE. Modify the variable $DestinationPath to suit your environment and then simply run the script.

The great thing is that you can re-rerun the script at any time to grab the latest updates I have made in that repository.

Office 365 services PowerShell bulk connection script

I spend a lot of my time logging in and out of various tenants using PowerShell. Some tenants require Multi Factor Authentication (MFA), others don’t. Sometimes I need to just use SharePoint Online or maybe Exchange and Teams.

Already having all the appropriate online services connection scripts in my Github repo here:

I wanted a way to make it easy for me to login to any tenant, MFA or not, as well as an service, or combination of services. Thus my latest script at:

provides a neat solution I believe.

They way it works is that:

1. You need to copy all the files from my Github repo to a directory on your local environment.

2. Execute the o365-connect-bulk.ps1 script where all the scripts are with following command line options:

-mfa if MFA required for login

-std if Microsoft Online connect required

-aad if Azure AD connect required

-exo if Exchange Online connect required

-s4b if Skype for Business Online connect required

-sac if Security and Compliance Center connect required

-spo if SharePoint Online connect required

-tms if Microsoft Teams connect required

-aadrm if Azure AD Rights Management connect required

You can combine some or all of these onto the command line like so:

.\o365-connect-bulk.ps1 –mfa –exo –tms

which will do a login with MFA for Exchange Online and Microsoft Teams. Or:

.\o365-connect-bulk.ps1 –std –spo

which will login with no MFA to Microsoft Online and SharePoint Online.

The way that I use scripts is to break them down into small scripts. I don’t like the idea of large ‘mega’ scripts that do everything because they are harder to maintain and when they break they are harder to debug. This way, o365-connect-bulk.ps1 relies in the other stand alone scripts in the same directory which it calls as needed.

The down side to this approach is that you may need to login to the tenant multiple times as each independent script runs. That is only initially and a small price to pay for the added flexibility and functionality I would suggest.

If need to login to many different tenants and services throughout the day then this bulk connection script should help you.

Update to SharePoint Online PowerShell module

Since the beginning of working with SharePoint Online with PowerShell you have had to download and install a stand alone MSI for access to the SharePoint Online cmdlets as I have detailed here:

Connecting PowerShell to SharePoint Online

Well no more! Yeah! Now you can install the module directly from PowerShell using the command:

Install-Module -Name Microsoft.Online.SharePoint.PowerShell

You should uninstall the old MSI version if you have it first.

Whee you run this command you should see the modules being installed like so:


and then you should be good to go.


This will make working with SharePoint Online via PowerShell so much easier!

The current version is 16.0.8212.0 and can be found here:

Centralised Office 365 Add in deployments with PowerShell

The three common Outlook add-ins I suggest be deployed across the entire organisation are:

1. Report Message

2. Message Header Analyzer

3. FindTime

You can allow users to deploy these individually but that opens up potential security concerns if users can install their own add ins. The better way is to deploy these centrally for all everyone.

You can do this using the Admin center in Office 365 but an even smarter way is to use PowerShell to do this, especially if you are going to install these add ins in multiple tenants.

To achieve this with PowerShell you are firstly going to have to go download and install the:

Office 365 Centralized Deployment PowerShell

which will allow you to deploy add ins using PowerShell commands.

Once you have installed this software go and fire up PowerShell command editor. You’ll need to connect/login to this service using the command:


but I’ve made connecting to the service easy for you by uploading a connection script to my GitHub repository here:

The thing to note about the connection is that this services doesn’t appear to support MFA identities so you’ll need to use an admin account that doesn’t have MFA enabled on it.

Once you have connected you’ll need to install the add in into the tenant using the command:


when you do this you’ll need to know the ‘Asset ID’ of the add in, which you will find in the URL for that add in in the store. The asset id appears in the form of WA104381180 for example. However, rather than you hunting around for these I’ve got them for you here:

Report Message = WA104381180

Message Header Analyzer = WA104005406

Findtime = WA104379803

The full command looks like:

New-OrganizationAddIn -AssetId ‘WA104381180’ -Locale ‘en-US’ -ContentMarket ‘en-US’

make sure you change the Locale and ContentMarket options to suit your environment.

You’ll then need to enable the add in within the tenant using the command:


for this you’ll need to the ‘Product Id’ of the add in. You can find that by running the command:


Here are the Product Id’s for my recommended add ins:

Report Message  = 6046742c-3aee-485e-a4ac-92ab7199db2e

Message Header Analyzer = 62916641-fc48-44ae-a2a3-163811f1c945

FindTime = 9758a0e2-7861-440f-b467-1823144e5b65

The full command to enable the add in within the tenant looks like:

Set-OrganizationAddIn -ProductId 6046742c-3aee-485e-a4ac-92ab7199db2e -Enabled $true

Finally, you’ll need to assign the add in to users. In this case, I believe these add ins should be mandatory for all users. Thus you run the command:

Set-OrganizationAddInAssignments -ProductId 6046742c-3aee-485e-a4ac-92ab7199db2e -AssignToEveryone $true

to do this.

Now you are all done and those add ins will roll out to every user in your tenant.

To read more about the PowerShell options available to you with PowerShell and centralised add in deployment check out this from Microsoft:

Use the Centralized Deployment PowerShell cmdlets to manage add-ins

I have also made the full deployment scripts for these three add ins available on my GitHub repository to save you time. You’ll find that script here:

That should make deploying your favourite Office add ins into Office 365 easier.