Accessing Microsoft Graph Data with Powershell
Published Feb 16 2023 03:00 AM 14.1K Views
Microsoft

 

Hi Mike Resnick here, as Azure AD Graph and Azure AD powershell modules heading for a well deserved retirement, I’m fielding a lot of similar “How to “questions around Azure based process automation and Microsoft Graph. 

Based on these conversations and automations I helped create for our clients, I put together a list of methods accessing Microsoft Graph with a brief description of each and where to use them. 

 

I will focus on Powershell based automation to the exclusion of Logic Apps, I did a webinar on using Logic Apps with Microsoft Defender for Cloud and will put a blog focused on Logic Apps and Microsoft Graph later this year.   

Feel free to use comments to share other ways you used to access Microsoft Graph 

 

Accessing Microsoft Graph interactively 

This is a set of default methods using predesigned Powershell cmdlets. Requires at a minimum 'Microsoft.Graph.Authentication' module. I recommend installing only modules you are going to use in your scripts, rather than the whole SDK. 

 

Using built-in SDK Cmdlets with delegated permissions 

Powershell Graph SDK  is a Microsoft's preferred method of working with Microsoft Graph via Powershell.

SDK cmdlets wrap Microsoft API calls for you and created default output in a PSObject format reducing the need to discover individual calls and methods.

 

There are, however, some drawbacks to using all Powershell Graph SDK Cmdlets 

  • You must rely on SDK authors to fix bugs in inputs or outputs 
  • Powershell pipeline does not work – cannot pass objects between CmdLets 
  • SDK CmdLets do not handle paging or throttling well 
  • SDK v1 does not work with Managed Identity Natively  
  • A number of SDK v1 CmdLets do not work unless ‘beta’ Graph version is specified  

 SDK v2  is currently available in public preview and fixes of the issues described above.

 

In my work with customers, I use cmdlets when I need to do a single 'write' task like configuration changes or a simple query that's expected to return no more than 100 objects, but as new capabilities are added I will start adding native SDK cmdlets to my tool kit. 

 

Find Application with word 'Dev' in display name 

This is a simple example getting a list of users and requires 'Microsoft.Graph.Applications' module besides 'Microsoft.Graph.Authentication'. Scope must be specified in the initial connect cmdlet or Get-MgApllcations will return "Insufficient Permissions' error. 

 

Connect-MgGraph -Scopes 'Application.Read.All' 

Get-MgApplication -ConsistencyLevel eventual -Search '"DisplayName:Test"'

 

More examples can be found in the Powershell Graph SDK Reference documentation  

 

Find Application with word 'Dev' in display name using Microsoft Graph Beta 

 

In some cases, you might want to use Microsoft Graph API Beta endpoint as, oftentimes, they contain more data or some of the Powershell Graph SDK cmdlets works only when 'beta' version is specified. 

 

Connect-MgGraph -Scopes 'Application.Read.All' 

Select-MgProfile beta 

Get-MgApplication -ConsistencyLevel eventual -Search '"DisplayName:Test"'

 

 

Using Microsoft Graph API direct call with Powershell Graph SDK and delegated permissions 

 

SDK Direct call method negates some of the disadvantages of using pure Powershell Graph SDK cmdlets, while still abstracting authentication and authorization. However, because Microsoft Graph API Odata filters use both single and double quotes as well as characters like '$', you may have to work around powershell's text parsing when building complex filters.  

 

 

Find all registered applications and retrieve id and Display Name 

 

This example is useful when you want to get data quickly or test Graph URL and Graph Explorer is not available. You can find further information on the “Consistency” header in Microsoft Graph Advanced Query Capability document. 

 

For large data sets you can add a loop to handle paging. 

 

Connect-MgGraph -Scopes 'Application.Read.all' 

$results = Invoke-MGGraphRequest -Method get -Uri 'https://graph.microsoft.com/v1.0/applications/?$select=id,displayName' -OutputType PSObject -Headers @{'ConsistencyLevel' = 'eventual' } 

$results.value

 

 

Powershell Graph SDK loop to handle paging 

 

 To avoid throttling loop is paused for 3 seconds. 

 

if (!([string]::IsNullOrEmpty($results.'@odata.nextLink'))) 

 { 

         

    do { 

        $results = Invoke-MGGraphRequest -Method get -Uri $results.'@odata.nextLink'  -OutputType PSObject -Headers @{'ConsistencyLevel' = 'eventual'} 

        $results.value 

        Start-Sleep -Seconds 3 

        } while (!([string]::IsNullOrEmpty($results.'@odata.nextLink'))) 

         

    } 

 

 

Accessing Microsoft Graph for automated tasks 

 

Most examples below are targeted towards Azure serverless scenarios such as Automation Runbooks v5.1 and Azure Functions V2 Powershell v7.2 but can be adopted to run on VM as well. 

All script samples need to have the required Microsoft Graph permissions set prior to execution. 

 

Using Managed Identity without Powershell Graph SDK 

 

With this method no additional Powershell SDK Modules are needed, and it works in any environment where Az.Accounts module is supported. 

However, data comes in json format only and needs additional parsing code, especially if you have to handle paging. This method cannot be used for Advanced Queries , as it does not have an option to add headers to the request. 

 

Connect-AzAccount -Identity 

$results = (Invoke-AzRestMethod -Uri 'https://graph.microsoft.com/v1.0/groups?$filter=startswith(displayName, ''GiveMeAccess'')&$select=id').Content | ConvertFrom-Json -Depth 99 

$results.value 

 

 

Using Managed Identity with Powershell Graph SDK 

 

This method uses a workaround to integrate Managed Identity with Powershell Graph SDK and allows to execute Advanced Queries because of the ability to pass custom headers. However, with Azure Automation Runbooks, it only works with Powershell Version 5.1. This may change in the future. 

 

Connect-AzAccount -Identity -Environment 'AzureCloud' 

$AccessToken = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token 

 

$headers = @{ 

    'ConsistencyLevel'= 'Eventual' 

 

} 

Connect-MgGraph -AccessToken $AccessToken -Environment 'Global' 

$results = Invoke-MGGraphRequest -Method get -Uri 'https://graph.microsoft.com/v1.0/applications/?$select=id,displayName&$count' -OutputType PSObject -Headers $headers 

$results.value 

 

Example to handle paging available above 

 

Using Powershell Graph SDK with Certificate Based Authentication with Azure Automation Runbooks 

 

This method is supported natively by both Azure Automation and Powershell Graph SDK and confirmed to work in Azure Automation Runbook Powershell 5.1 runtime. 

 

  1. To use this method you would need to register Azure AD application and grant the application rights to Microsoft Graph to execute task you would like to automate 
  2. Obtain a certificate, see example for self-signed certificate you can use for testing 
  3. Upload certificate with private key to Azure Automation account 
  4. Upload certificate with public key to the Application Certificates and Secrets 

 

Connect-AzAccount -Identity -Environment 'AzureCloud' 

$certificate = Get-AutomationCertificate -Name "<insert name of saved certficate entry in Azure Automation>" 

$headers = @{ 

    'ConsistencyLevel'= 'Eventual' 

 

} 

Connect-MgGraph -ClientId "<insert your app clinet id here>" -Certificate $certificate -Environment Global -TenantId "<insert your tenant id here>" 

 

Invoke-MGGraphRequest -Method get -Uri 'https://graph.microsoft.com/v1.0/applications/?$select=id,displayName&$count' -OutputType PSObject -Headers $headers 

#alternative option 

 

Select-MgProfile beta 

Get-MgApplication -ConsistencyLevel eventual -Property 'id','displayName' 

 

 

Using base powershell no Az or Powershell SDK Modules 

 

This method allows for the most flexibility, since you are using built in Powershell modules, and can be used anywhere including Linux based containers. You are also less likely to run into problems with Az and Powershell SDK modules. However, you are also responsible for securely storing and retrieving credentials, error checking, addressing paging and, if your task requires multiple calls and runs for more than an hour, you will need to add way to identify expired access token and then re-authenticate to obtain a new one. To use this method, you need to perform following steps: 

 

  1. Start by  registering Azure AD application and grant the application rights to Microsoft Graph to execute task you would like to automate 
  2. Generate and save application client secret 
  3. Replace Tenant Id, client id and client secret and run code below to get a list of applications  

 

$uri = "https://login.microsoftonline.com/<insert tennat id>/oauth2/v2.0/token" 

$clinet_id = <insert client id> 

$client_secret = <insert client secret> 

$queryURI = 'https://graph.microsoft.com/v1.0/applications/?$select=id,displayName&$count' 

$scope = [System.Web.HTTPUtility]::UrlEncode("https://graph.microsoft.com/.default") 

 

#Generating header values 

$tokenRequestQueryHeaderss =@{ 

    ContentType = "application/x-www-form-urlencoded" 

} 

 

#Create body to pass when requesting access token 

$body = "client_id=$($clinet_id)&scope=$($scope)&client_secret=$($client_secret)grant_type=client_credentials" 

 

#Send a post request to obtain bearer token 

$result = Invoke-RestMethod -Uri $uri -Body $body -Method Post -Headers $tokenRequestQueryHeaderss 

 

#Generate Header for query by adding Access Token obtained earlier 

$queryHeaders = @{ 

    Authorization = "Bearer $($result.access_token)" 

} 

 

#Send request  

$queryResult = (Invoke-RestMethod -Headers $queryHeaders -Body $body -Uri $queryURI  -Method Get).value 

 

$queryResult 

 

 

Thanks for reading!

 

 

 

Disclaimer
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.

 

 

1 Comment
Co-Authors
Version history
Last update:
‎Feb 16 2023 07:44 AM
Updated by: