Accessing Microsoft Graph Data with Powershell

This post has been republished via RSS; it originally appeared at: Core Infrastructure and Security Blog articles.

 

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 

 

  1. 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

 

 

 

 

 

Leave a Reply

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

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.