Adding support for selecting ALL properties using '*' wildcard in Mg Graph commands 'property' parameter

Ondrej SebelaOndrej Sebela
4 min read

Problem

You may have noticed that Microsoft Graph SDK commands like Get-MgUser, Get-MgDevice, etc don't retrieve all properties by default. ๐Ÿ‘‡

All object properties are returned, but most of them are empty.

What you need to do, is explicitly specify all properties you want to retrieve ๐Ÿ‘‡

This approach has at least two problems:

  • Only properties you explicitly specify are returned (check BusinessPhones property โ˜) a.k.a. you always need to specify "obvious" properties like name, id, etc which you'll need in 99% of situations anyway, plus required "extra" properties

  • You can use the wildcard '*' in the command property parameter, however, '*' doesn't return all properties as we are used to from AzureAD cmdlets. Instead '*' returns only a small subset of all properties as can be seen in the Get-MgUser -Debug example below ๐Ÿ‘‡


TL;DR

Use my proxy function Get-MgUser2 from my module PowerShell MSGraphStuff.

It supports the usage of '*' in the property parameter and unlike the official Get-MgUser command, returns all properties.


Solution

OK, so how can we easily return all properties without explicitly specify one by one?

Oneliner

What can come to your mind is to retrieve all available property names using Get-Member command right? So code like this should do the job

$mgUserProperty = Get-MgUser -Top 1 | Get-Member -MemberType NoteProperty, Property | select -ExpandProperty Name

Unfortunately, when we try to retrieve all available properties, Get-MgUser will fail with the error: "No OData route exists that match template ~/entityset/key with http verb GET for request /StatelessOnboardingService/users..."

I found out that it is caused by the property DeviceEnrollmentLimit, which therefore needs to be excluded.

Ok, next round. Now we try to get all properties without DeviceEnrollmentLimit. But it errors again ๐Ÿ˜„

Uncle Google gives me the answer for this error. It is caused by the property MailboxSettings which can be gathered only if you call Get-MgUser upon the account that was used for authentication to Graph API.

Ok, next round, and finally we have all properties returned without any error ๐Ÿ‘

# get all available property names
$mgUserProperty = Get-MgUser -Top 1 | Get-Member -MemberType Property | select -ExpandProperty Name

# return all properties (without the problematic ones)
Get-MgUser -UserId johnd@contoso.com -Property ($mgUserProperty | ? {$_ -notin 'DeviceEnrollmentLimit', 'MailboxSettings'})

Proxy function

As we saw in the previous section there are properties that cause troubles therefore simple oneliner cannot be used. So I've decided to create a proxy function Get-MgUser2 that alters how the original Get-MgUser handles '*' wildcard in the property parameter and at the same time solve issues with properties DeviceEnrollmentLimit, MailboxSettings.

Get-MgUser2 function is part of my PowerShell module MSGraphStuff, feel free to install it using Install-Module.

How proxy function Get-MgUser2 was created?

There are a lot of tutorials about creating PowerShell proxy functions. I've personally used this one.

In general, you retrieve the original function metadata (not the function code itself), wrap it into the new function and customize it as you like.

  1. Code for creating a proxy function (in this case Get-MgUser2 from original Get-MgUser).
# name of the function you want to create proxy function for
$originalCmdletName = "Get-MgUser"
# name of the new proxy function
$proxyFunctionName = "$originalCmdletName`2"
# where ps1 file with proxy function will be saved
$proxyFunctionLocation = "C:\proxyFunctions"

# get original command metadata
$metadata = New-Object System.Management.Automation.CommandMetaData (Get-Command $originalCmdletName)

# use metadata to create proxy function and save the result to the file
$proxyFunctionBody = @"
function $proxyFunctionName {
    $([System.Management.Automation.ProxyCommand]::Create($metadata))
}
"@

# create proxy function definition and save it in C:\proxyFunctions\Get-MgUser2.ps1 file
[Void][System.IO.Directory]::CreateDirectory($proxyFunctionLocation)
$proxyFunctionBody | Out-File "$proxyFunctionLocation\$proxyFunctionName.ps1"

Code can be used to create a proxy function for any command, just replace value in $originalCmdletName variable

  1. Now that we have the proxy function definition, we need to customize it to suit our needs. A.k.a. if '*' wildcard will be used in the property parameter: retrieve all available properties (without the problematic ones) and use them instead of '*'. The screenshot below shows what I've added to make it happen.

    original proxy function modifications

And that's it. The same approach can be used to create any proxy function ๐Ÿ‘.

TIP: pipe output of Graph commands to Format-Custom to expand all those nested objects. This is great for comparisons etc...

0
Subscribe to my newsletter

Read articles from Ondrej Sebela directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ondrej Sebela
Ondrej Sebela

I work as System Administrator for more than 10 years now and I love to make my life easier by automating work & personal stuff via PowerShell (even silly things like food recipes list generation).