How to use Microsoft Graph REST API Docs for PowerShell users

How to use the Graph API for PowerShellers

Before you start, I want to tell you that this is my way of working with the Microsoft Graph API & PowerShell.

It may be that you don’t like this & that you prefer another way and that’s fine too.
It would be nice if you share this in the comments.

I’ve noted the steps for a quick look and I explain the steps below in detail in a separate chapter.

I’ll use ‘List User’ as an example in the blog post.


A short explanation about how I work with a new Microsoft Graph API call in PowerShell.

  • I almost always scroll to the examples first to see how the requests are structured and what the result is what you get back.
    I often use this as an example for my own requests.
  • The value in the HTTP request is the relative path for the API.
    You need to add the correct endpoint: https://graph.microsoft.com/XXXX.
    Where XXXX stands for v1.0 or beta.
    When I don’t get the output I want I switch from v1.0 to beta.
    Looking at the Method I know which cmdlet I am using from my module. Get-Mga, Put-, Post-, ~
  • What exactly do I need and how many objects are involved?
    When it comes to 100+ objects, I use the $top query as much as possible.
    Is this just the userPrincipalName? Then I use the query $select.
    Can I filter out the users via a property?
    Via the query parameters I can reduce the calls to the API & I don’t exceed the throttling limits.
  • The header contains additional information necessary for the request.
    You must provide at least the mandatory headers.
    This is almost non-existent with the Graph API. When it does occur I use the CustomHeader parameter.
  • Which properties should I add to my HashTable for the RequestBody and which types are expected?
    Are these strings, arrays, bool, int, ~?

And after that press the magic F5 or F8 and wait for the results.

Wondering if you’re adopting best practices for the Microsoft Graph API? Then look at this blog post:
Best practices, tips and tricks working with Microsoft Graph API in PowerShell


So, where do I start when I need something from the Microsoft Graph API?

The Microsoft Graph API has its own search function. Personally, I am not a fan of the search function because what you search for must match the title of the page.

How to read Microsoft REST API Docs for PowerShell users
How to read Microsoft REST API Docs for PowerShell users

Instead, I search on Google with the site:microsoft.com query.

When I use ‘Get User’ as an example, the first thing I start with is ‘Googling’ for:
List User Microsoft Graph API site:microsoft.com

The ‘List Users‘ is the first result.


We’ve got the Microsoft Graph API, what now?

The Table of Contents is shown on the right of the screen.
In general it is the same for all Graph references.

How to read Microsoft REST API Docs for PowerShell users
How to read Microsoft REST API Docs for PowerShell users

Permissions

The permissions in this table are important.
The permissions you see below are listed from least to most privileged. Which means that your registered application needs one of these permissions, but with the leftmost permission it can execute this API call.

Permission typePermissions (from least to most privileged)
Delegated (work or school account)User.ReadBasic.All, User.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All, Directory.AccessAsUser.All
Delegated (personal Microsoft account)Not supported.
ApplicationUser.Read.All, User.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All
How to read Microsoft REST API Docs for PowerShell users

It is wise not to give an application more permissions than necessary.
With the idea that when the application is compromised, the hacker does not get more permissions than was necessary within your environment.

This is called the ‘principle of least privilege’.

To add permissions to you registered application you can follow the steps here.

I don’t recommend reusing a Registered application and instead always create a new application and give it the fewest permissions possible.
And always have the Authorization done with a certificate.

For what you do with PowerShell and my Optimized.Mga module you always need an registered application.
The idea behind this application is that you can run scripts without logging in as a person. That is why we need to use the Application permission.

Microsoft Graph has two types of permissions:

  • Delegated permissions are used by apps that have a signed-in user present. For these apps, either the user or an administrator consents to the permissions that the app requests and the app can act as the signed-in user when making calls to Microsoft Graph. Some delegated permissions can be consented by non-administrative users, but some higher-privileged permissions require administrator consent.
  • Application permissions are used by apps that run without a signed-in user present. For example, apps that run as background services or daemons. Application permissions can only be consented by an administrator.

Source: Microsoft.com


HTTP request

the HTTP request is the URL you use for Invoke-RestMethod or Get-Mga.

The HTTP request shows the method (Get) & relative path to the correct API call.
You have to add the endpoint yourself.

There are 2 different ‘endpoints‘:

The v1.0 will remain as is & the beta may change in the future.

I always try the v1.0 reference first and when I make the call and don’t get the values back I expect, I try the beta.
On the left side of the page you can see which reference is used by the docs.

How to use Microsoft REST API Docs for PowerShell users
How to use Microsoft REST API Docs for PowerShell users

When you switch reference versions, different properties may be requested for the body, header, content-type, or queries.

Depending on the method you use a cmdlet in my module.
The cmdlets contain the Method in the name:

  • Get-Mga
  • Post-Mga
  • Put-Mga
  • Delete-Mga
  • Patch Mga

With Invoke-RestMethod you have to use the method parameter.

For more about the Methods I’d like to refer your to the official Microsoft docs.


Optional query parameters

How important the query parameters are depends on what you want to do.

Suppose you only need to request one user and you want to request as many properties as possible, then it is not necessary to use a query,

Get-Mga -URL https://graph.microsoft.com/v1.0/users/[email protected]

but this concerns ‘List Users’ which means that we will request a certain number of users.

Suppose you need the users including all retrievable properties, then it is still useful to use a query parameter, why?
Because by default the Graph API returns 100 objects ​​and with the $top query you can adjust this to a maximum of 999.

(Get-Mga -URL 'https://graph.microsoft.com/v1.0/users' -Once).count

100

(Get-Mga -URL 'https://graph.microsoft.com/v1.0/users?$top=999' -Once).Count

999

That means you make 9 calls less to the Graph API.
The chance of hitting the throttling limits is significantly reduced that way.

Suppose you only need the userPrincipalName?
Then you can also use the $select query.

Get-Mga -URL 'https://graph.microsoft.com/v1.0/users?$top=999&$select=userPrincipalName' -Once

userPrincipalName
-----------------
[email protected]
[email protected]
[email protected]
[email protected]

This ensures that you have even less chance of exceeding the throttling limits.

look as much as possible at the query parameters that you can use for the relevant Microsoft Graph API call and how you can use them.

For more about the query parameters check this page:
Use query parameters to customize responses – Microsoft Graph | Microsoft Docs


Request headers

The request Header is mainly important for people who don’t use my module.
If you do use my module, it won’t happen often unless you’re uploading files or doing other specific tasks.

The header contains additional information necessary for the request.
For example, the authorization is your token to validate that you are allowed to make the call.

When you use the Connect-Mga cmdlet the authorization token it is saved in your global scope and automatically refreshed when it expires (the token expires after one hour).

$ConnectMgaSplatting = @{
    ClientSecret = 'XXXXXX'
    ApplicationID = 'XXXXXX'
    Tenant = 'cab50820-6873-42d9-8d79-f1bcad910f35'
}
Connect-Mga @ConnectMgaSplatting

$global:MgaheaderParameters


AuthKey   : Authorization
Value : Bearer eyJ0eXAiO~

For the users who work with Invoke-RestMethod, the Header is the parameter Headers.

Invoke-RestMethod -Method Get 'https://graph.microsoft.com/v1.0/users?$top=999&$select=userPrincipalName' -Headers $MgaheaderParameters


@odata.context : https://graph.microsoft.com/v1.0/$metadata#users(userPrincipalName)
value          : {@{[email protected]}

Unfortunately, ‘List Users‘ doesn’t have that many headers which is generally not the case with the Graph API.

If you do want to add an extra header to one of the cmdlets of the Optimized.Mga module, you can use the CustomHeader parameter.
It works the same as the Headers parameter of Invoke-RestMethod and after the call the header is automatically reverted to the original header.

For example, this is what I’m using in my Upload-MgaSharePointFiles cmdlet in this blog post & this API call.

$Header = @{}
$Header.Add('Content-Length', $LocalFileBytes.Length)
$Header.Add('Content-Range', $contentRange)
$Header.Add('Content-Type', 'octet/stream')

$UploadResult = Put-Mga -URL $uploadUrlResponse.uploadUrl -InputObject $LocalFileBytes -CustomHeader $Header

Request body

Because List Users uses the Get method, which means you only get information, you don’t have a request body.

You use a request body when, for example, you are going to create a user and have to provide the properties of the user with your request.

You do this by using the InputObject parameter in my module under the appropriate cmdlets and with Invoke-RestMethod you can use the Body parameter.

To elaborate on this, I switch to the Create User API call for now:
Create User – Microsoft Graph v1.0 | Microsoft Docs

Always look carefully at the request body to see which properties are mandatory. These are often listed separately in a table:

‘The following table lists the properties that are required when you create a user:.’

ParameterTypeDescription
accountEnabledbooleantrue if the account is enabled; otherwise, false.
displayNamestringThe name to display in the address book for the user.
onPremisesImmutableIdstringOnly needs to be specified when creating a new user account if you are using a federated domain for the user’s userPrincipalName (UPN) property.
mailNicknamestringThe mail alias for the user.
passwordProfilePasswordProfileThe password profile for the user. For Azure B2C tenants, the forceChangePasswordNextSignIn property should be set to false and instead use custom policies to force password reset at first sign in.
userPrincipalNamestringThe user principal name ([email protected]).
How to use Microsoft REST API Docs for PowerShell users

The parameter names are case sensitive. So keep this in mind!
Read the description carefully because it often contains valuable information. As you can see we don’t need to add the property onPremisesImmutableId because we don’t use federated services.
Look closely at the type they expect and carefully build your HashTable.

If we only grab the mandatory properties, your HashTable should look like this:

$User = [PSCustomObject]@{
    userPrincipalName = $UserPrincipalName
    displayName       = $Username
    accountEnabled    = 'true'
    mailNickname      = $Username
    passwordProfile   = [PSCustomObject]@{
        password                      = 'H78302ehpib'
        forceChangePasswordNextSignIn = 'true'
    }
}
Post-Mga -URL 'https://graph.microsoft.com/v1.0/users' -InputObject $User


id                : e65aba63-a8b0-4f19-b479-e8f6798e8829
businessPhones    : {}
displayName       : test.test.test

userPrincipalName : [email protected]

With the Optimized.Mga module you don’t have to worry about the ObjectType.
The cmdlets automatically convert it to Json-format and use the correct content-type for the request.

With Invoke-RestMethod you need to make sure that your HashTable is converted to Json with the ConvertTo-Json cmdlet. The Invoke-RestMethod also expects you to specify what type of content it is with the ContentType parameter. For json this is ‘application/json‘.

Invoke-RestMethod -Uri 'https://graph.microsoft.com/v1.0/users' -Body ( $User | ConvertTo-Json ) -Method Post -Headers $MgaheaderParameters -ContentType 'application/json'

Response

This states what kind of response you can expect in return.

I find it superfluous to look at the response when I already get this information from the examples.


Example

The examples are the most valuable to me.
In the example you can often see at glance how the call is made.

There is no tab for PowerShell in the examples yet, but the HTTP example is enough to understand what to use.

Here you can see how an existing call is made:

  1. This shows how the URL is formatted
  2. Which method you use
  3. The minimum request necessary
  4. Whether you have to specify the content-type

and, not in the screenshot, the answer you can expect in return.

How to read Microsoft REST API Docs for PowerShell users
How to read Microsoft REST API Docs for PowerShell users

Published by

Bas Wijdenes

My name is Bas Wijdenes and I work as a PowerShell DevOps Engineer. In my spare time I write about interesting stuff that I encounter during my work.

Leave a Reply

Your email address will not be published. Required fields are marked *