Graph API and Microsoft Graph SDK module tips & gotchas

Why I hate Microsoft Graph PowerShell modules... ๐Ÿ˜‰


5 min read

Table of contents

Several weeks ago I've started to migrate our PowerShell scripts from using soon-to-be-deprecated AzureAD and MSOnline modules and replace them with the Microsoft Graph SDK module.

During this time I came across various gotchas that I will summarize in this short post.

This post is from 9.2.2023 and is referring to Graph modules of 1.20.0 version.


Returned object properties can be CASE SENSITIVE ๐Ÿช“

  • For example cmdlet Get-MgDirectoryObjectById. Funny thing is that just the object saved in the property AdditionalProperties has case-sensitive properties. The main object properties aren't case sensitive ๐Ÿ˜ƒ

Documentation is terrible

  • It lacks examples. Especially unfortunate when an object has to be passed as an argument and you have no idea how it should look like.

  • It is crazy big (so it is super hard to find what you are looking for)

  • It is missing the description of the parameters

A lot of commands don't support pipeline?!

Like why can't I pass the output of the Get-MgUser to the Update-MgUser?!

Official 'Microsoft Graph PowerShell' Azure application isn't verified

  • If connecting to Graph API using Connect-MgGraph with new permission scope (aka you will have to grant consent), you will see a popup like below that shows the official Microsoft Graph PowerShell application as unverified. WTF Microsoft?!

There is a bug where every single cmdlet requests another authentication prompt

  • To fix this run: Remove-Item "$env:USERPROFILE\.graph" -Recurse -Force to clean the cache

Cmdlet Invoke-MgGraphRequest doesn't manage paging! So not all results will be returned at once and you need to solve this on your own

  • Just first 100 or so items will be returned (because of paging)

Graph cmdlets return all results only if All parameter is used!

  • Without All parameter just first 100 or so items will be returned (because of paging)

When you connect using a certificate and later in your code calls Connect-MgGraph it will display interactive auth. prompt

  • But if you connect using saved credentials, no following prompts will be shown

  • This super complicates unattended scripting. In such case, you probably use service principal and authenticate using certificate. But if such script calls any function or script that again calls Connect-MgGraph (because it is convenient to start your Graph code by making a connection), it will timeout/error.

Cmdlet Connect-MgGraph doesn't support the use of saved credentials

  • I've solved this by passing AccessToken

  • The new v2 version will support this, but for now, it is in the preview

Cmdlets don't have to return all properties values by default

  • The object with all available properties is always returned, but not all properties can be populated

  • The properties you want to retrieve can be specified by the Property parameter (Get-MgUser -Property DisplayName, Id) or parameter ExpandProperty if the property is expandable. Wildcard * isn't supported.

It's not obvious whether property or expandProperty parameter should be used to get the property data

  • For example Get-MgGroup command returns property Owners only if expandProperty parameter will be used! If you call it like Get-MgGroup -property owners , there will be no error, but also Owners property will be always empty no matter what! See this github issue.

Some commands return properties that will be always empty

For example Get-MgGroup returns property MembersWithLicenseErrors which is always empty because it is a relationship property and you have to use the command Get-MgGroupMemberWithLicenseError instead to get this data ๐Ÿ˜’


How to identify AzureAD and MSOnline deprecated modules usage in your scripts and get corresponding Graph commands

  • Check my post to get results like this ๐Ÿ‘‡

Always have all your Microsoft.Graph.* modules in the same version!

  • A.k.a. Microsoft.Graph.Authentication, Microsoft.Graph.Applications, ... in 1.20.0 version for example

  • Otherwise, you will see strange errors when trying to import a module with a different version

Some cmdlets need switching to the BETA version of the API for it to work (for example Invoke-MgInvalidateUserRefreshToken )

  • A.k.a. you need to call Select-MgProfile -Name Beta first

  • But don't forget to reverse to the stable API version ASAP!

    • new V2 version will have commands with special prefix when beta api will be used under the hood

Cmdlets with switch-type of parameters should use a colon to pass the switch value

  • A.k.a. New-MgInvitation -InvitedUserDisplayName $displayName -SendInvitationMessage:$true

Run Graph cmdlets with debug parameter to get more detailed information and called URI

Getting Graph command that works with specific API URI

Getting Graph URI that is used by the specific command

  • Find-MgGraphCommand -Command Get-MgUser | Select-Object URI

  • Use Chrome addon

  • Open the Azure or Intune page where the results you are interested in are shown >> press F12 to open Developer Tools >> switch to Network tab >> search for in the results

You should explicitly specify required scopes (permissions) when connecting to Graph API

Getting Graph permission required for specific command

Use Format-Custom to expand the returned objects properties

Filter query operators ne, not, endsWith needs to have ConsistencyLevel = 'Eventual' parameter set

Filter query operators ne, not, endsWith can be used only on some types of objects

For directory objects like users, the not and ne operators are supported only in advanced queries

  • A.k.a. consistencyLevel parameter has to be specified

Did you find this article valuable?

Support Ondrej Sebela by becoming a sponsor. Any amount is appreciated!