Stephan van Rooij

Software architect with a passion for home automation.

Extract all users with powershell and what to do about it part two


In a previous post I showed how to extract all users from a Microsoft 365 tenant, and what you should do about that. If you followed along that leak got restricted. The Azure AD module isn’t the only way to extract user information from a tenant. This post will show you how to do the same (extract all users to csv file) with the Graph PowerShell modules and what you should do about that.

Install Graph PowerShell modules

First you need to install some PowerShell modules:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser
Install-Module Microsoft.Graph.Users -Scope CurrentUser
# or just importing if previously installed
# Import-Module Microsoft.Graph.Authentication
# Import-Module Microsoft.Graph.Users

All available users to CSV

Let’s say you want all the available users in your tenant “safely” stored in a CSV file on your local machine.

# This will open a Microsoft login screen and save the resulting session
$graphSession = Connect-MgGraph -Scopes "User.Read.All"

# Create temp file
$filename = $(New-TemporaryFile).FullName + ".csv" # or "C:\temp\user.csv"

# This command will load the top 5 users, but you can modify this accordingly. It's just a demonstration....
# see
# it selects some properties (adjust accordingly)
# and exports to the filename
Get-MgUser -Top 5 `
  | Select-Object -Property Id,AccountEnabled,UserPrincipalName,Mail,GivenName,Surname,DisplayName,JobTitle `
  | Export-Csv -Path $filename

Write-Host "Users exported to $filename"

That was easy, 6 lines of “code” and you have a CSV file with all the users in your organization.

Is this a problem?

Not exactly, but it might be a problem if you have a lot of users. Such a csv file with hundreds/thousands users might be considered a data leak. Still no problem, because powershell is only for administrative accounts, right? RIGHT?? Wrong… By default EVERY user in your Microsoft 365 tenant is able to do this read action with powershell.

Restrict access to Graph powershell

Let’s see if we can find a way to prevent access for most users. As said this command Connect-MgGraph triggers a login screen, since I know which user logged-in to this PowerShell module at what exact time, I could directly find an entry in the Sign-in logs for this user, pointing me in the right direction.

Microsoft Graph PowerShell - Sign-in log

I found a login for application Microsoft Graph PowerShell with ID: 14d82eec-204b-4c2f-b7e8-296a70dab67e. This application did request access to Microsoft Graph with ID: 00000003-0000-0000-c000-000000000000 so the sign-in logs prove the Microsoft Graph PowerShell module is actually using the Graph API.

At first I opened Enterprise Applications, switched to Microsoft Applications and looked for Microsoft Graph. The idea was, if I find the Microsoft Graph PowerShell application there, I’ll just turn on User assignment required and only allow the few users I want.

Microsoft Graph Powershell - Not found

No luck there. It shows the resource application though, but I don’t want to mess with the Azure AD internals. The resource application Microsoft Graph SHOULD NOT BE TOUCHED. You will mess up a lot!

If you switch to All Applications the Microsoft Graph PowerShell application shows up. Just flip the switch Assignment required to Yes and press save. Go to Users and Groups and assign the application to the users who require it.

Microsoft Graph Powershell - Assignemnt required

Block Microsoft Graph module with PowerShell

By design not all options are shown on the Azure AD portal, and messing with options that are hidden by design might lead to unrecoverable results. Check the script below, careful, before executing (as with any script from a remote source).

This script uses powershell to change the service principal of the AzureAD application that is used to get tokens.

Connect-MgGraph -Scopes 'Application.ReadWrite.All'

$appId = "14d82eec-204b-4c2f-b7e8-296a70dab67e" # Microsoft Graph Powershell

# Get or create service principal
$sp = Get-MgServicePrincipal -Filter "appId eq '$appId'"
if (-not $sp) {
  $sp = New-MgServicePrincipal -AppId $appId

$ServicePrincipalUpdate =@{
    "appRoleAssignmentRequired" = "true"

Update-MgServicePrincipal -ServicePrincipalId $sp.Id -BodyParameter $ServicePrincipalUpdate

No more user access to this module

If some other user tries to use the Graph PowerShell modules, they are greeted with an AADSTS50105 error meaning you successfully blocked the application for other users. The error is descriptive enough for users who actually need this module to know what to do (ask the admin to grant access).

Microsoft Graph Powershell - Blocked

Unblock access to Graph PowerShell module

Connect-MgGraph -Scopes 'Application.ReadWrite.All'

$appId = "14d82eec-204b-4c2f-b7e8-296a70dab67e" # Microsoft Graph Powershell

# Get or create service principal
$sp = Get-MgServicePrincipal -Filter "appId eq '$appId'"
if (-not $sp) {
  $sp = New-MgServicePrincipal -AppId $appId

$ServicePrincipalUpdate =@{
    "appRoleAssignmentRequired" = "false"

Update-MgServicePrincipal -ServicePrincipalId $sp.Id -BodyParameter $ServicePrincipalUpdate


In my opinion this module and the one from the previous post should be blocked by default (maybe by the security defaults?) Be sure to share this post with all other system administrators you know. It will take them less then 5 minutes to block these modules and that makes their organization just a little more secure.

LinkedIn Profile Link Mastodon Follow on Twitter Check my blog

Batching with Microsoft Graph


Microsoft has this great api where you can control almost everything in the Microsoft 365 cloud. To speed up your requests, you can combine up to 20 requests in a batch. This post will explain how to use batching and how it got implemented in the Graph SDK for DOTNET.

Add users to group fast

Extract all Azure AD admin accounts


Powershell is pretty powerful for all kind of administrative tasks, especially if you load some extra modules. We use the AzureAD module for a lot of tasks that can be (semi-)automated with the use of some script. In this post I described how to extract all users from Azure AD as a regular user, and what you should do about it.

Extracting users isn’t the only thing you can do with Azure AD powershell and this page shows how to export all Azure AD global admins (which can be executed by ANY user in your tenant unless you take action against that.)

Like what you're seeing? Consider Sharing on Twitter or Sponsoring me