Microsoft Graph API

Quick tools & links

On this page you will find small helpful Graph API queries that can help you in operation or engineering. The topics will be added gradually and include any Microsoft Graph API products, such as Intune, Microsoft Entra ID, SharePoint and many more.

Microsoft Entra ID

Get Group by SID

This query can be used to resolve a group according to a SID. This can be helpful if a local group cannot be resolved by name in Intune managed Windows or only the SID is available in an output.

GET https://graph.microsoft.com/v1.0/groups?$filter=startsWith(securityIdentifier, '<yourgroupssid>')

Microsoft Graph Explorer basics

Requirements: Basic knowledge of HTTP REST communication

Basics

Microsoft Graph Explorer is a web-based tool to learn and test specific Graph API queries.

image.png

Microsoft Graph Documentation: https://learn.microsoft.com/en-us/graph/api/overview
Microsoft Graph Explorer: https://developer.microsoft.com/en-us/graph/graph-explorer

URL-Explanation

Protocol: The protocol defines on which Port the Request ist performed. Microsoft Graph only allows REST calls over HTTP with appropriate security (https:// over port 443).

Host: The Host sits between the protocol and the first slash ("/"). Hosts can be represented by IP Adress (e.g., 127.0.0.1) or Hostnames (graph.microsoft.com).

Route: API Routes are defined between the end of the top-level domain (e.g., .com) and the question mark ("?"). The route defines which path the program on the server should take and on which element it should perform the search or action.

Queries: URL queries are Located behind the question mark ("?") in the URL and are at the end of the whole URL.

image.png

Method selection

GET: Get specific or general information via JSON output object(s). 

POST: Submit some information via JSON, URL Encoded, XML, etc. and trigger some actions on the server. Returned values contains errors or success information and supports general information as well.

PATCH: Update some information on the server side from a client action. You must provide a object that gets updated and the content to which the object should be updated. (e.g., display name of some policy) 

PUT: Submit informations to a backend and don't get a response back.

DELETE: Delete object on specific path. Provide object which needs to be deleted, ether in URL itself or via body.

image.png

Things to consider & limitations

These things have to be considered when building automations or applications which use the Microsoft Graph API. 

Graph API limitations

This list documents the limitations of the Microsoft Graph API. The full limitations of the Microsoft Graph API can be seen here: Microsoft Graph service-specific throttling limits - Microsoft Graph | Microsoft Learn

Serverside data preperation to relieve clientside workload

Requirements: Basic Knowledge of Rest APIs and Microsoft Graph API

Graph API Query Parameters

With query parameters you can specify custom queries that the answer of the Graph API returns the values you need. Therefore, you specify the API Route you want to take and on this value you perform a serverside data preperation.

$Filter

Example: Get MEID Group Properties by MEID Group SID

GET https://graph.microsoft.com/v1.0/groups?$filter=startswith(securityIdentifier,'S-1-12-1-234774239-1265421194-1318151825-3905263908')

$Select

Example: Get Intune Primary User by Intune Device ID

GET https://graph.microsoft.com/beta/deviceManagement/managedDevices/<INTUNEDEVICEID>?$select=usersLoggedOn


Find API route, method & body in Microsoft web portals

Use Graph X-Ray AddOn

Graph X-Ray – Microsoft Edge Addons

With this add on for Microsoft Edge or Google Chrome you can see what the corresponding website is doing in the background and display the user interface commands directly in your favorite programming language.

  1. Open Chrome or Edge DevTools (F12).
  2. Go to the Graph X-Ray tab.
  3. Do the corresponding action in the browser on the Microsoft platform that uses Microsoft Graph.
  4. Then you will see the queries and parameters that the website used for your action.

image.png

Find API route

The API route describes the URL on which the requests are executed.

  1. Open developer tools in your browser. -> (F12 in Edge & Chrome)
  2. Open tab network tracing.
  3. Run query in GUI (Intune Admin Center, Azure Portal, etc.).
  4. Find query in Network Tracing.

image.png

Under General -> Request URL you can see the API route which was called from the corresponding web portal.

Find API method

To find out the REST method used, you can open the Devtools in the same way as for finding the API route. The network blade will then show which REST method was used under Request Method.

image.png

Find API body

Requirements: API route must be known (steps above)

When something is created, a JSON object must be passed to the API. Only the request method "POST" or "PUT" can be used.

  1. Open network tracing in browser.
  2. Perform query in GUI (Intune Admin Center, Azure Portal, etc.).
  3. Find query in network tracing.
  4. Switch to "Payload" and display JSON object.

image.png

Create application access token & authorization header

To authentication against the Microsoft Graph API there are two general concepts. Application permissions allow an application in Microsoft Entra ID to act as it's own entity, rather than on behalf of a specific user. Delegated permissions allow an application in Microsoft Entra ID to perform actions on behalf of a particular user.

This guide focuses on authentication as an application to create unattended automations. To create or renew a token in the user context there are other instructions.

Use case

This authentication is required if you want to retrieve, update, or create resources using the Microsoft APIs (Azure Management API, Microsoft Graph API). This is for application-based permissions such as regular or triggered automations.

Graph API authentication

To authenticate with application permission you have to use an Microsoft Entra ID App Registration. There you can specify an Client Secret as it is described here: Get app details and gr... | LNC Docs (lucanoahcaprez.ch)

The authentication method used for Microsoft Graph API is the industry-standard OAuth 2.0. This concept uses access tokens for authenticating against API endpoints. These access tokens are then sent to the resource server in the HTTP header. Therefore we have to create the header correctly to use the resources of the Microsoft Graph API.

image.png

Build header via PowerShell script

The following scripts creates the header that contains the header property and the corresponding Bearer token. This function needs the arguments Tenant ID, Client (Application) ID and the Client Secret. This function has to be called the first time with these three parameters. Then you can use the refresh token of the first authentication request to consist the session.

Attention: This function returns a complete header. If you want to specify more information in the request header you have to use the function lower on this page. 

# Function for getting Microsoft Entra ID Access Header
Function Build-MicrosoftEntraIDApplicationAccessHeader(){
    param(
        [Parameter(Mandatory=$true)]
        [string] $tenantid,
        [string] $clientid,
        [string] $clientSecret,
        [string] $refreshtoken
    )

    $authenticationurl = "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token"

    if($refreshtoken -and $tenantId){
        $tokenBodySource = @{
            grant_type = "refresh_token"
            scope = "https://graph.microsoft.com/.default"
            refresh_token  = $refreshtoken
        }
    }
    elseif($tenantId -and $clientid -and $clientSecret){
        $tokenBodySource = @{
            grant_type = "client_credentials"
            scope = "https://graph.microsoft.com/.default"
            client_id  = $clientid
            client_secret = "$clientSecret"
        }
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }

    while ([string]::IsNullOrEmpty($AuthResponse.access_token)) {
        $AuthResponse = try {
            Invoke-RestMethod -Method POST -Uri $authenticationurl -Body $tokenBodySource
        }
        catch {
            $ErrorAuthResponse = $_.ErrorDetails.Message | ConvertFrom-Json
            if ($ErrorAuthResponse.error -ne "authorization_pending") {
                Write-Error "Authorization not successful. Error while posting body source: $($ErrorAuthResponse.error)"
                throw
            }
        }
    }

    if($AuthResponse.token_type -and $AuthResponse.access_token){
        $global:MicrosoftEntraIDAccessToken = "$($AuthResponse.token_type) $($AuthResponse.access_token)"
        $global:MicrosoftEntraIDHeader = @{
            "Authorization" = "$global:MicrosoftEntraIDAccessToken"
        }
        Write-Output "Authorization successful! Token saved in variable."
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }
}

# Authorization Header with ClientId & ClientSecret
$tenantId="<tenantid>"
$ClientId="<appregistrationclientapp>"
$ClientSecret="<appregistrationclientsecret>"
Build-MicrosoftEntraIDApplicationAccessHeader -tenantid $tenantid -clientid $clientid -clientSecret $clientSecret

# Authorization Header with refresh_token
$tenantId="<tenantid>"
$refreshtoken="<yourrefreshtoken>"
Build-MicrosoftEntraIDApplicationAccessHeader -tenantid $tenantid -refreshtoken $refreshtoken

Get Bearer Token via PowerShell script

This function allows you to use more than one header property. It only returns the access token which then has to be built into a header by itself. But the other functionalities and parameters work like the function above. 

# Function for getting Microsoft Entra ID Access Token
function Get-MicrosoftEntraIDApplicationAccessToken {
    param(
        [Parameter(Mandatory=$true)]
        [string] $tenantid,
        [string] $clientid,
        [string] $clientSecret,
        [string] $refreshtoken
    )

    $authenticationurl = "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token"

    if($refreshtoken -and $tenantId){
        $tokenBodySource = @{
            grant_type = "refresh_token"
            scope = "https://graph.microsoft.com/.default"
            refresh_token  = $refreshtoken
        }
    }
    elseif($tenantId -and $clientid -and $clientSecret){
        $tokenBodySource = @{
            grant_type = "client_credentials"
            scope = "https://graph.microsoft.com/.default"
            client_id  = $clientid
            client_secret = "$clientSecret"
        }
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }

    while ([string]::IsNullOrEmpty($AuthResponse.access_token)) {
        $AuthResponse = try {
            Invoke-RestMethod -Method POST -Uri $authenticationurl -Body $tokenBodySource
        }
        catch {
            $ErrorAuthResponse = $_.ErrorDetails.Message | ConvertFrom-Json
            if ($ErrorAuthResponse.error -ne "authorization_pending") {
                Write-Error "Authorization not successful. Error while posting body source: $($ErrorAuthResponse.error)"
            }
        }
    }

    if($AuthResponse.token_type -and $AuthResponse.access_token){
        $global:MicrosoftEntraIDAccessToken = "$($AuthResponse.token_type) $($AuthResponse.access_token)"
        Write-Output "Authorization successful! Token saved in variable."
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }
}

# Authorization with ClientId & ClientSecret
$tenantId="<tenantid>"
$ClientId="<appregistrationclientapp>"
$ClientSecret="<appregistrationclientsecret>"
Get-MicrosoftEntraIDApplicationAccessToken -tenantid $tenantid -clientid $clientid -clientSecret $clientSecret

# Authorization with refresh_token
$tenantId="<tenantid>"
$refreshtoken="<yourrefreshtoken>"
Get-MicrosoftEntraIDApplicationAccessToken -tenantid $tenantid -refreshtoken $refreshtoken


Create user access token & authorization header

To authentication against the Microsoft Graph API there are two general concepts. Application permissions allow an application in Microsoft Entra ID to act as it's own entity, rather than on behalf of a specific user. Delegated permissions allow an application in Microsoft Entra ID to perform actions on behalf of a particular user.

This guide focuses on authentication as a user to create scripts in the context of the provided user. To create or renew a token in the application context there are other instructions.

Use case

This authentication is required if you want to retrieve, update, or create resources using the Microsoft APIs (Azure Management API, Microsoft Graph API). This is for delegated-based permissions such as user triggered scripts or automations.

Graph API authentication

To authenticate with application permission you have to use an Microsoft Entra ID App Registration. There you can specify an Client Secret as it is described here: Get app details and gr... | LNC Docs (lucanoahcaprez.ch)

The authentication method used for Microsoft Graph API is the industry-standard OAuth 2.0. This concept uses access tokens for authenticating against API endpoints. These access tokens are then sent to the resource server in the HTTP header. Therefore we have to create the header correctly to use the resources of the Microsoft Graph API.

image.png

Get access token from Graph Explorer

The simplest variant can be used for one-off tokens or scripts that are rarely executed by the user. The code can simply be copied out under “Access token” in Microsoft Graph Explorer. It is also important that “Bearer” is added at the front (in the scripts that are provided here, the "Bearer" addition is made in the respective API call) and that the permissions for each Graph Endpoint are set under “Modify permissions”.

image.png

If the permission were recently granted, refresh the page a few times or be a bit more patient ;)

Build header via PowerShell script

The following scripts creates the header that contains the header property and the corresponding Bearer token. This function needs the arguments tenant ID, client (Application) ID, the client secret, the username and the password. This function has to be called the first time with these parameters.

Attention: This function returns a complete header. If you want to specify more information in the request header you have to use the function lower on this page. 

# Function for getting Microsoft Entra ID Authentication Header
function Build-MicrosoftEntraIDUserAuthenticationHeader {
    param (
        [Parameter(Mandatory=$true)]
        [string] $TenantId,
        [string] $ClientId,
        [string] $ClientSecret,
        [string] $Username,
        [string] $Password,
        $Refreshtoken
    )

    $authenticationurl = "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token"

    if($refreshtoken -and $tenantId){
        $tokenBodySource = @{
            grant_type = "refresh_token"
            scope = "https://graph.microsoft.com/.default"
            refresh_token  = $refreshtoken
        }
    }
    elseif($tenantId -and $clientid -and $clientSecret){
        $tokenBodySource = @{
            client_id = $clientId
            scope = 'https://graph.microsoft.com/.default'
            grant_type = 'password'
            username = $username
            password = $password
            client_secret = $clientSecret
        }
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }

    while ([string]::IsNullOrEmpty($AuthResponse.access_token)) {
        $AuthResponse = try {
            Invoke-RestMethod -Method POST -Uri $authenticationurl -Body $tokenBodySource
        }
        catch {
            $ErrorAuthResponse = $_.ErrorDetails.Message | ConvertFrom-Json
            if ($ErrorAuthResponse.error -ne "authorization_pending") {
                Write-Error "Authorization not successful. Error while posting body source: $($ErrorAuthResponse.error)"
                throw
            }
        }
    }

    if($AuthResponse.token_type -and $AuthResponse.access_token){
        $global:MicrosoftEntraIDAccessToken = "$($AuthResponse.token_type) $($AuthResponse.access_token)"
        $global:MicrosoftEntraIDHeader = @{
            "Authorization" = "$global:MicrosoftEntraIDAccessToken"
        }
        Write-Output "Authorization successful! Token saved in variable."
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }
}

# Authorization Header with ClientId, ClientSecret and User Credentials
$tenantId="<tenantid>"
$ClientId="<appregistrationclientapp>"
$ClientSecret="<appregistrationclientsecret>"
$Username = "<yourusername>"
$Password = '<yourpassword>'
Build-MicrosoftEntraIDUserAuthenticationHeader -ClientId $ClientId -TenantId $tenantId -ClientSecret $ClientSecret -Username $Username -Password $Password

# Authorization Header with refresh_token
$tenantId="<tenantid>"
$refreshtoken="<yourrefreshtoken>"
Build-MicrosoftEntraIDUserAuthenticationHeader -TenantId $tenantId -refreshtoken $refreshtoken

Get Bearer Token via PowerShell script

This function allows you to use more than one header property. It only returns the access token which then has to be built into a header by itself. But the other functionalities and parameters work like the function above. 

# Function for getting Microsoft Entra ID Access Token
function Build-MicrosoftEntraIDUserAccessHeader {
    param (
        [Parameter(Mandatory=$true)]
        [string] $TenantId,
        [string] $ClientId,
        [string] $ClientSecret,
        [string] $Username,
        [string] $Password,
        $Refreshtoken
    )

    $authenticationurl = "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token"

    if($refreshtoken -and $tenantId){
        $tokenBodySource = @{
            grant_type = "refresh_token"
            scope = "https://graph.microsoft.com/.default"
            refresh_token  = $refreshtoken
        }
    }
    elseif($tenantId -and $clientid -and $clientSecret){
        $tokenBodySource = @{
            client_id = $clientId
            scope = 'https://graph.microsoft.com/.default'
            grant_type = 'password'
            username = $username
            password = $password
            client_secret = $clientSecret
        }
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }

    while ([string]::IsNullOrEmpty($AuthResponse.access_token)) {
        $AuthResponse = try {
            Invoke-RestMethod -Method POST -Uri $authenticationurl -Body $tokenBodySource
        }
        catch {
            $ErrorAuthResponse = $_.ErrorDetails.Message | ConvertFrom-Json
            if ($ErrorAuthResponse.error -ne "authorization_pending") {
                Write-Error "Authorization not successful. Error while posting body source: $($ErrorAuthResponse.error)"
                throw
            }
        }
    }

    if($AuthResponse.token_type -and $AuthResponse.access_token){
        $global:MicrosoftEntraIDAccessToken = "$($AuthResponse.token_type) $($AuthResponse.access_token)"
        Write-Output "Authorization successful! Token saved in variable."
    }
    else{
        Write-Error "Authorization not successful. Not enough information provided."
    }
}

# Authorization Header with ClientId, ClientSecret and User Credentials
$tenantId="<tenantid>"
$ClientId="<appregistrationclientapp>"
$ClientSecret="<appregistrationclientsecret>"
$Username = "<yourusername>"
$Password = '<yourpassword>'
Build-MicrosoftEntraIDUserAuthenticationHeader -ClientId $ClientId -TenantId $tenantId -ClientSecret $ClientSecret -Username $Username -Password $Password

# Authorization Header with refresh_token
$tenantId="<tenantid>"
$refreshtoken="<yourrefreshtoken>"
Build-MicrosoftEntraIDUserAuthenticationHeader -TenantId $tenantId -refreshtoken $refreshtoken

Lookup external tenant id

Requirements: Authorization header and CrossTenantInformation.ReadBasic.All permission on App Registration. 

With this API endpoint you can check if the domain is registered on Microsoft 65 products and get the tenant name and tenant id by a random domain name.

Use case

This API can be used to lookup a domain name to check if this company or domain is using Microsoft 365.

Graph API

This API route can be used to lookup the tenant id and tenant name.

GET https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByDomainName(domainName='<domain>')

{
    "@odata.context": "https://graph.microsoft.com/beta/$metadata#microsoft.graph.tenantInformation",
    "tenantId": "<tenantid>",
    "federationBrandName": null,
    "displayName": "<tenantdisplayname>",
    "defaultDomainName": "<tenantonmicrosoftdomainname>"
}

Response: 200 OK

If the domain is not registered inside Microsoft 365, this API route returns a 404 Error.

Send mail via Exchange Online

Requirements: Authentication header is needed to use this script and API.

Basic API information

This API can either be used to send a mail out of the mailbox of a user (application permission needed):

POST https://graph.microsoft.com/v1.0/users/<userprinciplename>/sendMail

Or to send mails out of the own mailbox (delegated permission needed):

POST https://graph.microsoft.com/v1.0/me/sendMail

JSON Body

{
    "message": {
        "subject": "<subjectofemail>",
        "body": {
            "contentType": "Text",
            "content": "<contentofemail>"
        },
        "toRecipients": [
            {
                "emailAddress": {
                    "address": "<recipientemail1>"
                }
            },
            {
                "emailAddress": {
                    "address": "<recipientemail2>"
                }
            }
        ],
        "ccRecipients": [
            {
                "emailAddress": {
                    "address": "<ccrecipientemail1>"
                }
            },
            {
                "emailAddress": {
                    "address": "<ccrecipientemail2>"
                }
            }
        ]
    },
    "saveToSentItems": "true"
}

HTTP Response

The HTTP Response in a successful submission is:
202 Accepted

Permissions

This script uses Graph API and authenticates with an App Registration, so it can be used in application permission mode to send mails out of automated powershell scripts. The App Registration needs the following Microsoft Graph permission:

Mail.Send

This permission can be set either as application permission or as delegated permission.

PowerShell script

This PowerShell script sends an email to specified people in Recipients and CCRecipients variables.  The subject, senderupn and content of the mail can be provided on the function "Send-Mail".

function Send-Mail {

    param (
        [String]$SenderUPN,
        [Array]$Recipients,
        [Array]$CCRecipients,
        [String]$Subject,
        [String]$Content
    )
  
    $MailBodyJSON = @"
  {
    "message": {
      "subject": "$Subject",
      "body": {
        "contentType": "Text",
        "content": "$Content"
      },
      "toRecipients": [],
      "ccRecipients": []
    },
    "saveToSentItems": "true"
  }
"@
  
    $MailbodyObject = ConvertFrom-JSON $MailBodyJSON
    Foreach($Recipient in $Recipients){
        $RecipientBodyJson = @"
  {
    "emailAddress": {
        "address": "$Recipient"
    }
  }
  "@
        $RecipientBodyObject = ConvertFrom-JSON $RecipientBodyJson
        $MailbodyObject.message.toRecipients += $RecipientBodyObject
    }
  
    Foreach($CCRecipient in $CCRecipients){
        $CCRecipientBodyJson = @"
  {
    "emailAddress": {
        "address": "$CCRecipient"
    }
  }
"@
        $CCRecipientBodyObject = ConvertFrom-JSON $CCRecipientBodyJson
        $MailbodyObject.message.ccRecipients += $CCRecipientBodyObject
    }
  
    $MailoutputbodyJson = ConvertTo-JSON $MailbodyObject -Depth 10
  
  
  
    Write-Host "Sending Mail to $Recipient and $CCRecipient (CC)."
    Invoke-RestMethod -Method Post -Uri "https://graph.microsoft.com/v1.0/users/$SenderUPN/sendMail" -Headers $Header -ContentType "application/json" -Body ([System.Text.Encoding]::UTF8.GetBytes($MailoutputbodyJson))
  }
  
  $Recipients = @("<recipient1>","<recipient2>")
  $CCRecipients = @("<ccrecipient1>","<ccrecipient2>")
  
  Send-Mail -SenderUPN "<senderupn>" -Recipients $Recipients -CCRecipients $CCRecipients -Subject "<subject>" -Content "<content>"

Use Case

This Script can be used in any automation script to send mails securely over the Microsoft Graph API. This is an easy to use mechanism to modernize a script with modern authentication.

Example: 

In a Runbook you can get all App Registrations and check for each one if the secret is soon to be expire. If the secret expires in X days, it sends a reminder mail to the owner(s) of the App Registration.