Starting from Dec 2022 we will need to use the Get MgUser cmdlet to get and export our Azure AD users. Get-MgUser is part of the Microsoft Graph SDK for PowerShell. It allows us to interact with all Microsoft Services through a single endpoint.
All the user accounts in your Microsoft 365 tenant are stored in the Azure Active Directory. We can manage them through the admin center or Azure Portal, but sometimes is PowerShell more convenient.
In this article, I am going to explain how we can use the Get MgUser cmdlet to find and retrieve user information from the Azure AD. I have also created a complete script that allows you to export all your users to CSV, which you will find at the end of the article.
Getting started with Get-MgUser
Before we can start, make sure that you have installed the Microsoft Graph Module in PowerShell. In this article, you can find a complete guide on how to install the module.
The Get MgUser cmdlet allows you to find and extract user information from the Azure Active Directory. There are a couple of parameters that we can use to find or filter the users:
- UserId – Return specific user based on UPN or ObjectID
- Filter – Retrieve multiple objects based on a oDate v3 query
- Search – Get all users that match the searchString
- Top – Return n number of results
- All – Return all results (by default the first 100 items are returned)
Good to know is the cmdlet returns only the first 100 results by default. So make sure that you use the -all
parameter to get all results when needed.
So the first step is to connect the Microsoft Graph with the correct scope. We are only going to retrieve user data, so we can use the User.Read.All
scope.
Connect-MgGraph -Scopes 'User.Read.All'
To test if the cmdlet is working you can simply get all users from your Azure Active Directory with the following cmdlet:
Get-MgUser -All
To get a single user we can use the UserId of the user. This can either be the UserPrincipalName of the user or the actual user id:
# Get the user by the UserPrincipalName Get-MgUser -UserId [email protected] # Get the user by the actual id: Get-MgUser -UserId 7a3b301d-0462-41b6-8468-19a3837b8ad1
Using Filters with Get-MgUser
Just like with the Get-AzureAduser cmdlet we can filter the users. The filter is based on the oDate v3 query, but not all operators are supported. We can only use the following operators to filter to users:
Operator | Description | Example |
---|---|---|
eq | Equals to | jobtitle eq ‘Marketing Assistant’ |
and | And | jobtitle eq ‘Recruiter’ and jobtitle eq ‘hr’ |
or | Or | jobtitle eq ‘Recruiter’ or jobtitle eq ‘hr’ |
startswith | String starts with | startswith(jobtitle,’recr’) |
Important is that you wrap the filter query in double-quotes and the string that you want to filter on in single-quotes. Only when you filter on a boolean you don’t need to put quotes around the true or false statement.
So let’s take a look at a couple of examples using the -filter
parameter. To find a user by the display name we can specify the complete name of the user or use the startsWith operator. Keep in mind that we can’t use wildcard or the -like
operator here.
# Find the user based on the full name Get-MgUser -Filter "DisplayName eq 'Adele Vance'" # Find the user by the first part of the name Get-MgUser -Filter "startsWith(DisplayName, 'A')"
The same method can also be used to get all users with the job title “Marketing Assistant” for example:
Get-MgUser -Filter "jobtitle eq 'Marketing Assistant'"
To get for example only the enabled user accounts with the Get-MgUser cmdlet we can use the following command:
Get-MgUser -Filter 'accountEnabled eq true' -All
Note that I have added the -all parameter. By default, the Get MgUser cmdlet only returns the first 100 results. By adding the -all
parameter we get all the results returned.
We can also filter on multiple conditions, by using and
or or
in the filter query:
Get-MgUser -Filter "department eq 'Marketing' and jobtitle eq 'Manager'"
Another example that I would like to share is the option to get all users that are created last year. For this, we can filter the CreatedDateTime property:
Get-MgUser -Filter "CreatedDateTime ge $((Get-Date).AddYears(-1).ToString("s"))Z"
Using Search to Find Users
Besides the filter parameter, we can also use the -Search
parameter to find users. The parameter requires a property that you want to search on and a value. You will also need to set the -consistencylevel
to eventual
.
The advantage of the -search parameter is that it allows us to search on any part of the value. So for example, if want to search on a part of the name we can use :
Get-MgUser -Search 'DisplayName:van' -ConsistencyLevel eventual
Also, note that you will need to wrap the search query in single quotes. You can use the search parameter on pretty much all the fields that are returned by the Get-MgUser cmdlet.
Combining Search and Filter in Get MgUser
We can also combine the -search and -filter parameters in one command. This allows us to search on a name or job title among enabled accounts only for example:
Get-MgUser -Filter 'accountEnabled eq true' -Search 'DisplayName:van' -ConsistencyLevel eventual
Selecting Properties to Return
When using the Get-MgUser cmdlet you have probably noticed that it doesn’t return a lot of properties by default. Most fields are empty or contain the value Microsoft.Graph.PowerShell.Models. followed by an entity name. So how do we retrieve this data?
There are two parameters that we can use to get the information that we need, -property
and -expandproperty.
The -property
parameter is just like the select
that we can pipe behind the cmdlet. The only difference is that with select, all data is returned by Microsoft Graph and filtered out in PowerShell.
Get-MgUser -UserId [email protected] | Select DisplayName,BusinessPhones,Mail,JobTitle DisplayName BusinessPhone Mail JobTitle ----------- ------------- ---- -------- Adele Vance {+1 425 555 0109} [email protected] Retail Manager
When you use the property parameter, only the data that you need is returned by Microsoft Graph. Especially when working with a lot of records this will be faster than using select.
Get-MgUser -UserId [email protected] -Property DisplayName,BusinessPhones,Mail,JobTitle | fl
If you output the results to a list, you will see that only the fields that you have selected with the property parameter contain data.
Expanding Microsoft.Graph.PowerShell.Models
When viewing the properties of a user you may have noticed that some of them contain the value Microsoft.Graph.PowerShell.Models followed by a resource name. These models (or resources) are relationships of the resource type that you are viewing.
These relationships should allow us to easily view the related data of the resource. If we take the user, we may want to know the manager of it.
To do this we will need to expand the properties and select the correct parameter of the manager object:
Get-MgUser -UserId [email protected] -ExpandProperty manager | Select @{Name = 'Manager'; Expression = {$_.Manager.AdditionalProperties.displayName}} # Result: Manager ------- Miriam Graham
The challenge with those relationships is to find the correct field and permissions that you need. We are now connected to Microsoft Graph with only the User.Read.All
scope. If we for example want to view the working hours of a user in the mailbox settings, then we first need to find and add the correct scope to our session.
To find the correct permission I like to use the Rest API documentation. If you expand a resource it will show the relationships of the resource. You can then click on the type which will take you to the related resource where you can find the required permissions.
So for the mailbox settings, we will need to add the MailboxSettings.Read
permissions:
Connect-MgGraph -Scopes "User.Read.All","MailboxSettings.Read"
And then we can select the property and nested values:
Get-MgUser -UserId [email protected] -Property MailboxSettings | Select @{Name = 'days'; Expression = {$_.MailboxSettings.WorkingHours.DaysofWeek}}
Script to get all Azure AD Users and Export to CSV
I have created a complete script that allows you to get and export all Azure Active Directory users to a CSV file. There are a couple of options when you run the script:
- Get the manager of the user – Default True
- Get enabled, disabled or both user accounts – Default True
- Set the export path for the CSV file – By default the location of the script
You can download the latest version of the script here from my GitHub repository. To run the script, simply navigate to the script location and run:
.\Get-MgUsers.ps1 -path c:\temp\users.csv
If you want to know more on how to run a script, or how to add your script location to your PowerShell profile, then make sure that you read this article.
<# .SYNOPSIS Get all Azure AD Users using Microsoft Graph with properties and export to CSV .DESCRIPTION This script collects all Azure Active Directory users with the most important properties. By default it will only get the enabled users, manager of the user and searches the whole domain. .OUTPUTS CSV with Azure Active Directory Users .NOTES Version: 1.0 Author: R. Mens - LazyAdmin.nl Creation Date: 15 feb 2022 Purpose/Change: Initial script development .EXAMPLE Get all AzureAD users from the whole Domain .\Get-MgUsers.ps1 -path c:\temp\users.csv .EXAMPLE Get enabled and disabled users .\Get-MgUsers.ps1 -enabled both -path c:\temp\users.csv Other options are : true or false .EXAMPLE Don't lookup the managers display name .\Get-MgUsers -getManager:$false -path c:\temp\users.csv #> param( [Parameter( Mandatory = $false, HelpMessage = "Get the users manager" )] [switch]$getManager = $true, [Parameter( Mandatory = $false, HelpMessage = "Get accounts that are enabled, disabled or both" )] [ValidateSet("true", "false", "both")] [string]$enabled = "true", [Parameter( Mandatory = $false, HelpMessage = "Enter path to save the CSV file" )] [string]$path = ".\ADUsers-$((Get-Date -format "MMM-dd-yyyy").ToString()).csv" ) Function Get-Users { <# .SYNOPSIS Get users from the requested DN #> process{ # Set the properties to retrieve $properties = @( 'id', 'DisplayName', 'userprincipalname', 'mail', 'jobtitle', 'department', 'OfficeLocation', 'MobilePhone', 'BusinessPhones', 'streetAddress', 'city', 'postalcode', 'state', 'country', 'AccountEnabled', 'CreatedDateTime' ) If (($getManager.IsPresent)) { # Adding additional properties for the manager $select = $properties += @{Name = 'Manager'; Expression = {$_.Manager.AdditionalProperties.displayName}} $select += @{Name ="Phone"; Expression = {$_.BusinessPhones}} }else{ $select = $properties } # Get enabled, disabled or both users switch ($enabled) { "true" {$filter = 'AccountEnabled eq true'} "false" {$filter = 'AccountEnabled eq false'} "both" {$filter = ''} } # Get the users Get-MgUser -Filter $filter -Property $properties -ExpandProperty Manager | select $select } } Function Get-AllMgUsers { <# .SYNOPSIS Get all AD users #> process { Write-Host "Collecting users" -ForegroundColor Cyan # Collect and loop through all users Get-Users | ForEach { [pscustomobject]@{ "Name" = $_.DisplayName "UserPrincipalName" = $_.UserPrincipalName "Emailaddress" = $_.mail "Job title" = $_.JobTitle "Manager" = $_.Manager "Department" = $_.Department "Office" = $_.OfficeLocation "Phone" = $_.Phone "Mobile" = $_.MobilePhone "Enabled" = if ($_.AccountEnabled) {"enabled"} else {"disabled"} "Street" = $_.StreetAddress "City" = $_.City "Postal code" = $_.PostalCode "State" = $_.State "Country" = $_.Country "Account Created on" = $_.CreatedDateTime } } } } # Check if MS Graph module is installed if (Get-InstalledModule Microsoft.Graph) { # Connect to MS Graph Connect-MgGraph -Scopes "User.Read.All" }else{ Write-Host "Microsoft Graph module not found - please install it" -ForegroundColor Black -BackgroundColor Yellow exit } Get-AllMgUsers | Sort-Object Name | Export-CSV -Path $path -NoTypeInformation if ((Get-Item $path).Length -gt 0) { Write-Host "Report finished and saved in $path" -ForegroundColor Green # Open the CSV file Invoke-Item $path }else{ Write-Host "Failed to create report" -ForegroundColor Red }
Wrapping Up
The Microsoft Graph SDK for PowerShell is still pretty new and not well documented at the moment of writing. So it can be a bit of a challenge to find the correct syntax or cmdlet to get the information that you need.
I hope this article helped you to get started with the Get MgUser cmdlet. If you have any questions just let me know in the comments below.
is there a way to have stored credentials for Azure as a secured xml file or something so when this is run it doesn’t prompt for credentials?
You could look at the ConvertTo-SecureString cmdlet to store the password. But keep in mind that this isn’t 100% secure. If someone gains access to the file they could gain administrator access. So when taking this approach, I recommend to create an unique account for the script and limit the permissions as much a possible.
I need to get email or UPN for over 2,000 user starting with a csv file containing their display names (from Dataverse, CoE). Here’s what doesn’t work (with error messages):
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter “(displayname eq $own.owner)”)}
Get-MgUser_List1: Invalid filter clause
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter (displayname eq “$own.owner”))}
displayname: The term ‘displayname’ is not recognized as a name of a cmdlet, function, script file, or executable program.
But this reads and writes my csv file fine:
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(echo “$own.owner”)}
And this works fine for one user (without the csv):
get-mguser -consistencylevel eventual -filter “(displayname eq ‘Kushner, Rick [USA]’)”
Try this:
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter "(displayname eq $($own.owner))")}
Rudy, could you explain this syntax? Do you understand why it works?
The problem was the filter. You will need to use the string interpolation ($($own.owner)) to get the owner value from the each record.
Great work, Rudy
The move to Graph is a necessity, so your info is a valuable resource!
Highly recommend adding the Graph x-ray dev tool to your browser.
From the portal gui, gives you an equivalent Graph command in a side window that you can try.
Graph explorer is also a goldmine of info for this.
Thank you for your efforts helping the IDAM community!
Chris
How about filtering based on a list in a .csv?
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter “displayname eq ‘$own.owner'”)}
… or …
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter (displayname eq “$own.owner”))}
… or …
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter “(displayname eq $own.owner)”)}
None of them work!!!
Here it is!
foreach ($own in import-csv -path c:\Users\580616\DistinctOwners.csv) {(get-mguser -consistencylevel eventual -filter “(displayname eq ‘$($own.owner)’)”)}
When creating a new user from csv, how can we add the manager field to the script and import properly?
What about setting details? I want to add a number of mobile phone numbers, etc.
You will have to use the Update-MgUser cmdlet
Additional to this, is there a way to pull in the email or UserPrincipalName for a Manager
$select = $properties += @{Name = ‘Manager’; Expression = {$_.Manager.AdditionalProperties.displayName}}
I tried replacing displayName but then there is no value written at all.
A couple of options:
get-mguser -UserId [email protected] -ExpandProperty manager | Select @{Name = 'Manager'; Expression = {$_.Manager.AdditionalProperties.mail }}
or
$user = get-mguser -UserId [email protected] -ExpandProperty manager
$user.Manager.AdditionalProperties.mail
Thanks for this but “-All” is a parameter that cannot be found – on line 63.
Any Ideas?
Is it the same line as line 91 here on GitHub?
Great script! Thank you for providing it. It’s a good foundation that I can build-on, as requirements change. I suggest just one change though. Since the script is described to get all AAD users, add “-All” to line 101.
It already is but behind the properties parameter. But I would expect it near the filter as well to be honest.
Great script and really insightful.
Do you know if it is possible to filter the user list so that only user accounts where the employeeId extension attribute is populated with a value are returned, and all other user accounts are ignored and not in the CSV file?
I’m a Powershell newbie, and cant figure how to do that in PS using the Graph SDK with the limiting filtering options.
You will need to first select all users, and then run a where filter on them. The attributes are in the OnPremisesExtensionAttributes parameter which you will need to expand first:
Get-MgUser -All | Select -ExpandProperty OnPremisesExtensionAttributes
Hi, another question that I can’t seem to find how to get OtherEmails field. if I try to request it as a property, I get System.String[] and if I do “get-mgUser -ExpandProperty OtherEmails”
I get:
get-mgUser : Parsing OData Select and Expand failed: Could not find a property named ‘OtherEmails’ on type ‘microsoft.graph.user’.
At line:1 char:1
+ get-mgUser -ExpandProperty OtherEmails
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: ({ ConsistencyLe…stem.String[] }:f__AnonymousType54`9) [Get-MgUser_List], RestException`1
+ FullyQualifiedErrorId : BadRequest,Microsoft.Graph.PowerShell.Cmdlets.GetMgUser_List
Any ideas where to find it?
You have a small typo, the property is called othermails.
Get-MgUser -Property OtherMails | Select -ExpandProperty OtherMails
Hi – great write up and fully agree the lack of documentation is a big hurdle in moving away from Azure AD Powershell.
Question – the powershell standard output works fine, but writing to a CSV causes letters with accents to be converted to question marks. Any idea on how to write to CSV with correct encoding?
Try adding
-Encoding utf8
to the Export-CSV commandHi there
Many thanks for your work here.
I’m trying to export a similar list but including users who have $null strong/modern authentication methods but I don’t think you can expand the property authentication as it simply returns Microsoft.Graph.PowerShell.Models.MicrosoftGraphAuthentication on a basic query and This operation target is not yet supported if you attempt to expand.
Have you any ideas?
Regardless, many thanks for the insight.
Regards
Marty