Category: IdefixBlog

Staled Azure AD users


Have you ever thought “Do we have full controll over our offboarding routine?” then this script is perfect in your toolbox for checking for inactive users in Azure Active Directory.

I am stumbling across several Azure Active Directories where there are one or more user account enable and active without beeing in use by someone. That can be personal accounts not used anymore or it could be system accounts thats not in use.

In this post I`ll focus on a script where we get a output as a CSV file on when users last logged into their account.


Create a App Registration within your Azure AD! You can use this guide official Microsoft Learn guide

Remember to take note from:
* Tenant ID
* Application ID
* Application Secret

And your newly created App Reg need a API permission
* AuditLog.Read.All
* User.Read.All

Script content

The script can be downloaded from my Github repostitory

The first part of the script is a set of variables that you need to change before running the script

$contentType = "application/json"
$exportpath = "'.\User_Signin_Activity.csv'"

$Body = @{    
    Grant_Type    = "client_credentials"
    Scope         = ""
    client_Id     = "YOUR CLIENT ID"
    Client_Secret = "YOUR CLIENT SECRET"

Here we need to add your Tenant ID from your Azure Tenant and a Client ID (Application ID) and Client Secret from your app reg.
You can also set a Export path where the final result will be stored as a CSV.

The next part of the script is connecting to the Graph API authorizing as your App Registration witch has Audit log read and User read access and start getting users for the first page.

$ConnectGraph = Invoke-RestMethod -Uri "$tenantID/oauth2/v2.0/token" -Method POST -Body $Body

$token = $ConnectGraph.access_token
$headers = @{ 'Authorization' = "Bearer $token" }

$queryURL = '$select=displayName,createddatetime,userprincipalname,mail,usertype,signInActivity,accountEnabled,companyName'
$SignInData = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $headers -contentType $contentType
$relLink = $SignInData.'@odata.nextLink'

Next the script will loop through users page for page and collect data within a variable called $outlist and when it`s done looping through all users it will export the result into a CSV file.

$outList = @()
while ($SignInData.'@odata.nextLink' -ne $null){
   foreach ($relLink in $SignInData.'@odata.nextLink') {
      Write-Output "Getting data from $relLink"
      $SignInData = Invoke-RestMethod -Method GET -Uri $relLink -Headers $headers -contentType $contentType

          foreach ($user in $SignInData.Value) {
            If ($Null -ne $User.SignInActivity)     {
               $LastSignIn = Get-Date($User.SignInActivity.LastSignInDateTime)
               $DaysSinceSignIn = (New-TimeSpan $LastSignIn).Days }
            Else { #No sign in data for user
               $LastSignIn = "Never or > 90 days" 
               $DaysSinceSignIn = "N/A" }

              $Values  = [PSCustomObject] @{
                  UPN                = $User.UserPrincipalName
                  DisplayName        = $User.DisplayName
                  Email              = $User.Mail
                  Created            = Get-Date($User.CreatedDateTime)
                  LastSignIn         = $LastSignIn
                  DaysSinceSignIn    = $DaysSinceSignIn
                  UserType           = $User.UserType
                  accountEnabled     = $user.accountEnabled
                  Company            = $user.companyName}
                $outList += $Values

$outList | Export-Csv -Path $exportpath -Encoding UTF8 -NoTypeInformation


This script is perfect for your toolbox when you need to do manual checks of how your user state are. This can easily be transferred into a Azure Runbook for scheduled execution.

Azure AD – Keep it clean and tidy

There are several reasons for keeping your Azure AD nice and tidy. Locking down features, removing unused objects and applications and so on – all this keep the the attack surface of your environment lower and makes it easier for you to manage your Azure AD, do access reviews on access groups, roles and so on. So for making it a bit more easy for you I will list out 5 tips for getting a more tidy and clean Azure AD.

First tips – M365 Groups

Lock down who can make “Microsoft 365 Groups”. By doing this you block users from creating houndreds of testing group and often (almost never) they don`t delete groups again.

This need`s to be done within Powershell, but in short notes we create a security group in Azure AD that contains the super users who is allowed to create M365 groups. Then we run a short PowerShell script for locking it down

See for full guide/documentation for this process


$GroupName = "<GroupName>"
$AllowGroupCreation = $False


$settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id
    $template = Get-AzureADDirectorySettingTemplate | Where-object {$_.displayname -eq "group.unified"}
    $settingsCopy = $template.CreateDirectorySetting()
    New-AzureADDirectorySetting -DirectorySetting $settingsCopy
    $settingsObjectID = (Get-AzureADDirectorySetting | Where-object -Property Displayname -Value "Group.Unified" -EQ).id

$settingsCopy = Get-AzureADDirectorySetting -Id $settingsObjectID
$settingsCopy["EnableGroupCreation"] = $AllowGroupCreation

  $settingsCopy["GroupCreationAllowedGroupId"] = (Get-AzureADGroup -SearchString $GroupName).objectid
} else {
$settingsCopy["GroupCreationAllowedGroupId"] = $GroupName
Set-AzureADDirectorySetting -Id $settingsObjectID -DirectorySetting $settingsCopy

(Get-AzureADDirectorySetting -Id $settingsObjectID).Values

Second tips – Naming convention M365

Since we already have locked down creation of groups we can aim to do the naming convention in two ways. We can create a provisioning solution where users can order their groups and from there we are setting names, members and having approval process for ordering.

We can also create namin convention rules in Azure AD where we can set a prefix and or suffix. This can be set by a attribute from the user object creating the group or by a fixed string.

Within this feature there is also a “Blocked words” list. This is a list that you can upload with blocked words so that users cannot creat or use words that you put on that list. A maximum of 5000 words can be added to this list.

Learn more about naming conventions here at

All settings are foud under “Azure AD – > Groups -> Settings”

Third tips – User attributes

Maybe not a tidy up and clean Azure AD tips – but I like to have good data quality in Azure AD so that many attributes can be used when creating dynamic groups, homemade scripts and so on. This tips is closely attached to the next tip for User provisioning. So please add as much information as possible on all user objects.

All of these attriutes must also match the organization in that manner so that we are not ending up with 1000 different departments that actually are the same.

Fourth tips – User provisioning

To make it easier for the entire organization and specially the IT department who are creating users, then the need of a easy user provisioning system is always there! Based on a provisioning system we can add more attributes without having users to type all of it.

An super easy user provisioning can just be a SharePoint Lists list in a company wide Teams Team called onboarding. Power Automate that creates a user disabled and based on “Employee Hire Date” we can user “Lifecycle workflows” within Identity Governance to do tasks a few days before users are starting in the company. In the pictures below we see how we can add input for user creation, and a Power Automate that created the user in Azure AD with all attributes added (and keeps it disabled). The last part is where the Lifecycle workflow`s runs and enable the user, add license and sends out a Temporarly Access Pass so that users can sign-in and setup the security for their account.

SharePoint list for onboarding
Power Automate for creating a user and keeping it disabled in Azure AD
Pre-hire tasks runned on user prior to hire date based on the SharePoint list input

Fifth tips – Enterprise applications

This tips is to keep good governance and security posture for applications that are connected to Azure AD. This is applications that connects to Azure AD to exstract information about signed in users and also can claim access for services that the end-user have access to – this can be mailbox for the user, Onedrive for business or sharepoint sites.

Malicious applications can therefore gain access to information and documents that they should not have access to when the end-user them self can approve the application access.

So we start with blocking for User concent for everyone.
head into “Azure AD -> Enterprise Applications -> Consent and permissions” and set both settings to “Do not allow user Consent” / “Do not allow group owner consent”

After we have done this we need to be sure that a administrator is getting notifications when users are trying to get consent for a application.
This can we do here – “Azure AD -> Enterprise Applications -> User settings” and set the settings like this.

The official documentation is at

How to keep up-to-date

So how do you keep yourself up to date on tech?

This is a question I get a lot and it`s a bit tricky question if you think about it.
Technology and of course Cloud solutions are in a rapid change at all times and to be able to be on top of all the changes is not possible at all.
For me, I gain my insight from several sources every day and it`s a continuous task to be up to speed on the topics that you like to follow.

My topics that i follow closely are these:

  1. Azure AD and all IAM related Azure news
  2. Endpoint Manager aka Intune
  3. Microsoft Defender (whole suite)

Other that these topics I do also keep an attention on – but the three on my list I keep an extra eye 🙂

So how do I manage to get information about topics and tech?
I use Twitter as main source and also keeping my eyes on the “What`s new” section for all the products I`m keeping track on.

Keep in mind that the list is a snapshot of how it looks today (31.10.2022) and will most likely be outdated already.

What`s new feed:

  1. Azure AD – 
  2. Intune –
  3. Microsoft Defender –
    1. Microsoft Defender suite has more services that are linked within this page.
  4. Windows 365 –
  5. Sentinel –

I`ll share three good twitter handlers to follow for getting more fresh information:

  1. @merill (
  2. @Alex_A_Simons (
  3. @Brinkhoff_C (

For a complete twitter list please have a look at my twitter profile and see who I am following 🙂

FIDO2 on break-the-glass = smart move!

We now have a new capability for choosing different MFA methods for a set of users using Conditional Access policies. And with that we can ensure that our most important users uses the most secure method for authenticating to our services.

Out of the box you can choose from these three MFA methods, but there are options for creating your own method also.

  • Multifactor authentication: this is basically the same as the ‘old’ Require multifactor authentication. It will request the user to enter its password and then request the MFA (using the default one the user has configured – MFA request, SMS…). This option does not really strengthen your MFA
  • Passwordless authentication: this option requires you have enable the Passwordless authentication method with Microsoft Authenticator or FIDO keys first. This improves the strength of your MFA authentication
  • Phishing-resistant authentication: this option requires you have enable the Passwordless authentication method with FIDO keys first. This provides the more strength of your MFA authentication


To be able to use this feature you need the following

Conditional Access

it`s quite easy to setup the new Conditional Access policy that – go here and do the following – (Azure AD -> Security -> Conditional Access) and create a new policy

Give the new policy a name and set users to your BTG account like this –

In the “Cloud Apps or actions” section select “All cloud apps” so that we are sure that this account get`s the promt on all applications.

Go to “Grant” and from there you can use the new feature called “Require authentication strenght” set this to “Phising-resistant” and you are good to go!

Activate the policy (Enable = On) and hit “Save”

Testing your account

When signing in to your BTG account first time after you enabled the Conditional Access policy that require that your user need`s FIDO2 to be able to sign-in you will be promted by this sign! “Secure your account” – “The organization require that you use one of the following methods to authenticate”

And as we see here – the only option is “FIDO 2 Security key” even tho for the rest of the organization we allow Authenticator App, SMS and Phone calls.

Require only FIDO2 on your account

So this message means that we need to use a Temporary Access Pass so that the user can update his MFA method.

Create a TAP for the user on the user object – AzureAD -> Users -> BTG Account -> Authentication methods.
Navigate to and sign-in with the TAP.

You can then setup your FIDO2 key for your user when you are signing into to

Take away`s

Even tho we require FIDO2 key for our user, we still need to authenticate with username and password before we are prompted for the FIDO2 key. This is since Conditional Access policies are only evaluated after primary authentication witch is Username + Password.

Multifactor usage

In this short blog I will show you how to look into if users are using Multifactor Authentication based on earlier posts on how to monitor and collect logging for your Azure AD.

So first of all – You need to setup Azure AD logging. Have a look at this blogpost to se how easy it is to setup. “Monitor Azure AD”

Then we need to use a query in Log Analytics. You find the latest version on my github or you can copy paste from the code-snippet under.

| where TimeGenerated > ago (14d)
| summarize ['Single-factor Auth.']=countif(AuthenticationRequirement == "singleFactorAuthentication"), ['MFA']=countif(AuthenticationRequirement == "multiFactorAuthentication") by bin(TimeGenerated, 1d)
| render timechart with (ytitle="Amount", title="MFA vs non-mfa last 14 days")

This query will give you an output like this when used. You can then use this in your monitoring solution to visualize the usage of MFA.

MFA usage vs Single factor usage

Monitor sensitive accounts


A pre-requisites for monitoring sensitive accounts in Azure AD is to have setup a Log Analytics Workspace and your Azure AD logs sent to Log Analytics. If you want to know how that`s done then have a look at this blog post to se how easy it is to enable in your tenant “Monitor Azure AD”


So to be able to monitor sensitive accounts we first need to locate/determine what accounts that you want to monitor. I always recommend to monitor the Break-the-glass administrator account so that you or your team is alerted whenever the account is used.

So in the Log Analytics query below here you see that we are searching the “SigninLogs” for a specific UserPrincipalName and we are only looking at ResultType 0. (ResultType 0 is equal for Success).

| where UserPrincipalName == ""
| where ResultType == "0"

So with that in mind let`s create a Alert Rule from this query so that we are notified every time “” doing a successful signin.

Log Analytics Workspace with query for a specific username and success login

So when clicking the “New Alert Rule” button we are headed into a new page with several settings. here I have changed only two tings;
Operator: Greater than or equal to
Threshold value: 1

Click Next to go to “Actions”

Action Group

An action group is how and who is getting notified when the alert is fired.
So we create a new action group for this scenario and setup a email warning to an administrator.

You can choose to also send a payload to a Azure Function, Webhook and more within the Action pane of the Action group – in this scenario we are only using the notification part so let`s skip to the “review and create” part and create the Action Group


We then give the alert a “Alert rule name” and a description. This is what`s in the email notification sent to the user or users in the Action group

Jump over to “Review + create” and create the Alert rule.

Conclusion and result

  • We have gained monitoring and notification by doing a Query in Log Analytics.
  • From the Logs pane we can easily create a new Alert rule
  • We created a Action Group where we spesified who and how to get notified

And the result looks like this when there is a sign-in from that account and the Alert rule is fired!

Secure your accounts

So now a days many have enabled MFA for their accounts. And that’s great!
It show`s that what we have been working on the last years is working. According to Microsoft, MFA can prevent 99,9% of attacks to your accounts. But there is a attack vector that not many think of.

Do you have full control over the process of onboarding new users?

We often se that users are created and activated several days before the user is actually starting to work. That means that in most of the onboardings the user account is not protected to MFA until the user is sign in in and enters the security information needed for activating MFA on the account.

What we see now is that hackers are executing brute force attacks on username and password of accounts that had never logged on into Azure AD.

So to protect us from this we need to establish a Conditional Access policy preventing users from the ability for enrolling to MFA except from when they are seated at the company (Location whitelist).

Steps for protecting your users

  • Login to and navigate “Azure AD” then head into “Security” -> “Conditional Access” -> “Named Locations” and create a new “IP ranges location”
  • Navigate “Policies” and hit “New policy” – then fill in a name for example; “require trusted location for MFA registration”.
  • Select “All users” in the “Users or workload identities”
  • Select “User actions” in the “Cloud apps or actions” section and checkmark the “Register security information”
  • Select “Locations” under “Conditions” and set “Configure” to yes and hit the “Exclude” section and there add your Named Location.
  • Go to “Grant” and select “Block Access”
  • Now your accounts need to be located at your named location to be able to do a registration of security information.

Monitor Azure AD

Main goal

Main goal for this blogpost is to gain more knowledge on how to collect logs from Azure AD. By default you`ll get 30 days audit and sign-in logs stored within Azure AD. To be able to interact / automate on the logs we need to move the logs to a Log Analytics Workspace. So by doing so we gain these and much more features on our log data:

  • Ability to automate actions based on logs
  • Increase retention time on logs
  • Connect Microsoft Sentinel

Speaking of retention time you can choose from 30, 31, 60, 90, 120, 180, 270, 365, 550, and 730 days within the Azure Portal on the Log Analytics Workspace.

Log Analytics

First of all you need to create a Log Analytics Workspace and to do that you need to have a Azure Subscription in place (and you need Contributor access to it).
– Create a “Resource Group”
– Create a “Log Analytics Workspace

Here i have created a Resource group and added a Log Analytics Workspace to that group named “idefix-sentinel-log-analytics”

Azure AD configuration

When the LAW (Log Analytics Workspace) is ready then you can configure Azure AD to send log`s directly to it.
Head into Azure AD and navigate to “Audit Logs” or “Sign-in logs” and from there click the “Export Data Settings”

Azure AD -> Audit Logs -> Export Data Settings

Here you click on “Add Diagnostics Settings” and give it a name, point it to the log analytics you created and choose what to store into that LAW.

Choose all categories you want to store

After you save it you should wait about 15-20 minutes before trying to query the logs, just to be sure that new log`s have been streaming into LAW.

Test query in Log Analytics

To query your data you need to navigate to your Log Analytics Workspace and head into the “Logs” pane and from there you can add a Query to search the log`s with.

Log Analytics Workspace -> Logs

This query gets all login entries for users whose name contains Julian

| where Identity contains "Julian"

To be more specific, use UserPrincipalName:

| where UserPrincipalName == ""

All sign-ins for Julian in the last 30 days

| where UserPrincipalName == ""
| where TimeGenerated > ago(30d)

MFA settings

In order to optain a secure infrastructure you need to have controll over your MFA settings. There are several settings you need to configure and know how it works.

In this post I`ll go through all settings like


Maybe the easiest setting but yet som important.
You need to configure who will get the notification whenever there is a issue with one of your users. To do this please go here and and your desired address:
Azure Active Directory > Security > Multi-Factor Authentication > Notifications

Fraud Alert

Fraud alert is verry important to configure! This feature will block signins for the end-user when the user is deny’ing a unknown or suspicious MFA promt on their Authenticator app or phone. The user is blocked in 90 days or until a Administrator un-blocks the user.
Head into – Azure Active Directory > Security > MFA > Fraud alert
And enable the “Fraud alerts” settings on your tenant.

Account Lockout

So this Multi-Factor feature will let you configure your environment to handle MFA request attacks. Meaning that you can configure the Account Lockout settings for how many denials before triggering a account lockout and also you can configure how many minutes until the counter resets.

The settings are set here: Azure Active Directory > Security > MFA > Account lockout

These are my recomended settings for this.

Block/Unblock users

So the Block / Unblock feature is a feature that allows you to block a user it their device is stolen or lost. The user you put on this block list is blocked for 90 days or until a Administrator unblocks the user.

Block a user: Azure Active Directory > Security > MFA > Block/unblock users.
Write in UPN and a reason for blocking.

Unblock a user: Azure Active Directory > Security > MFA > Block/unblock users.
Select unblock on the user you want to unblock and write a reason for unblocking.

New MFA capabilities in Azure AD

So these day`s we all uses MFA right? But not all MFA methods are as good as we think.

There have been several cases where “SIM Swapping” or “SIM Hijacking” has been the case and therefor – can we trust using SMS for Multi-Factor Authentication?

In short notes this is how SIM Swapping is done.

  1. You loose personal information.
  2. Your information is used to gain trust at the mobile carrier to convice them to switch from current to new SIM card (the new SIM is already in the hands of the bad guy)
  3. With controll of mobile number the bad guy log`s onto your services with one-time password or completing MFA challenge.
  4. Your account is compromised

With that said, you should disable SMS as an authentication method.
See my other blog post on how that`s done!

Since you now uses Microsoft Authenticator as your primary MFA factor you get a push notification with “Allow” or “Block” access whenever the authentication is done.
At this point the bad guy start using a method called “MFA Fatigue attacks” and blasts lot`s of authentications against you, and somethimes a user clicks on “Allow” and thinks; “It`s most likely my phone or tablet or something…”.

But with the new capabilities from Microsoft within using Azure MFA you can now add “Number matching” and “additional context” to the signin (both features are in preview at the momemt (04.05.2022).

OK – so here`s how it looks!

So you see that when ever the authentication is done a number is shown and it needs to be matched on your Microsoft Authenticatior application. In addition we also see a map and location of where the authentication is getting from!

Here`s how you can configure it!

  1. Head over to
  2. Navigate to Azure AD -> Security -> Authentication methods and click on “Microsoft Authenticator”
  3. Hit “Add users and Groups” and add a group or user to test with and click “Select”
  4. Then open the settings of the group and “Require number matching” and “Show additional context in notifications”

There you have it!
Next time you authenticate with a user that`s configured to this setting you will get a number matching 🙂