Skip to main content

Microsoft Graph API gives you the ability to interact with the continually evolving Azure services through a single endpoint: https://graph.microsoft.com. We are going to connect to Graph with Powershell, OAuth 2.0 and REST.

Registering your App

To interact with Graph we need to register our app. Go to https://portal.azure.com/#blade/Microsoft_AAD_RegisteredApps/ApplicationsListBlade to get started. Login with your account that is associated with your tenant. Add a new App and enter the following details:

  • Name > just give it a name
  • Application Type > Web-app/-API
  • Sign on Url > Doesn’t matter so we go for: http://localhost:8000

Then select you newly created App and goto Required permissions, here we are going to add the Graph API permission. You will need to select different permission depending on what you want to access. You can change this later, so for now we click Add on the top, select Microsoft Graph and in step 2 we just select Read and write access to user profile. 

The last step is to create a key, go to Keys and enter a Key Description and set the duration to Never Expires. When you click on Save the value (ClientSecret) will only be displayed once, so write it done when it’s displayed.

Become an ethical hacker that can hack computer systems like black hat hackers and secure them like security experts.

Authentication and Authorization

To access the Graph API we need to get an Access Code. If you are new to working with Rest and Graph API then there are a few things to keep in mind:

  1. To get an Access Token you need an Authorization Code. The code is only 1 hour valid, but as long as your refresh token is valid, you only need to renew this every 90 days.
  2. The Access Token, which is used in every request is only valid for 1 hour. You can renew it with the Refresh Token.
  3. The Refresh Token is valid for 14 days.

So the first step is to get the Authentication code. We use the script below for this. Run the scripts with :

1.  GraphAPIGetAuthCode.ps1 -ClientId <clientId> -ClientSecret <clientSecret> -RedirectUrl <redirectUrl>

It will store the Authentication code in a text file at the script root location. This way we can easily access it later.

Thanks to Darren Robinson: https://gist.github.com/darrenjrobinson/b74211f98c507c4acb3cdd81ce205b4f#file-ps2graphapi-ps1

Get the Access and Refresh Token

With the Authentication code we can get the all important Access token and the much needed refresh token. Because the Access token is only 1 hour valid, we need to check it’s age and request a new one with the refresh token if it’s expired.

The script below  stores the access and refresh token in text files in the script root location. You can always change it to store it just in variables, but keep in mind, when you close the shell it’s all gone and you need to start again with the Authorization code.

The scripts checks the last modified time of the accesstoken.txt, if it’s older than 1 hour, it will request a new access token with the refresh token. If that fails, it will request a new Authorization code and start from their again.

I use a config.json file to store my ClientId, ClientSecret and RedirectUrl, this way you can easily change it.

Config.json

1.  {
2.    "AppId": {
3.      "ClientId": "fa9d9d34-7a2a-****-****-************",
4.      "ClientSecret": "J/WDSKLjE+XC9G0+ASDHUen31/***********=",
5.      "RedirectUrl": "https://localhost:8000",
6.      "ResourceUrl": "https://graph.microsoft.com"
7.    }
8.  }

ConnectTo-Graph

1.  #----------------------------------------------------------[Declarations]----------------------------------------------------------
2.
3.  #Get the config file
4.  $config = Get-Content $PSScriptRoot"\config.json" -Raw | ConvertFrom-Json
5.
6.  # Add System Web Assembly to encode ClientSecret
7.  Add-Type -AssemblyName System.Web
8.
9.  # Encode ClientSecret
10. $clientSecretEncoded = [System.Web.HttpUtility]::UrlEncode($config.AppId.ClientSecret) 
11.
12. # Get the accessToken
13. If ((Test-Path -Path $PSScriptRoot"\accessToken.txt") -ne $false) {
14.   $accessToken = Get-Content $PSScriptRoot"\accessToken.txt"
15. }
16.
17. #---------------------------------------------------------[Initialisations]--------------------------------------------------------
18.
19. # Check if the AccessToken is not older then 1 hour
20. If (($accessToken -eq $null) -or ((get-date) - (get-item $PSScriptRoot"\accessToken.txt").LastWriteTime).TotalHours -gt 1) {
21.
22.   # Get the refreshToken
23.   $refreshToken = Get-Content $PSScriptRoot"\refreshToken.txt"
24.
25.   $clientId = $config.AppId.ClientId
26.   $clientSecret = $config.AppId.clientSecret
27.   $redirectUrl = $config.AppId.RedirectUrl
28.   $resourceUrl = $config.AppId.ResourceUrl
29.  
30.   Try {
31.     $refreshBody = "grant_type=refresh_token&redirect_uri=$redirectUrl&client_id=$clientId&client_secret=$clientSecretEncoded&refresh_token=$refreshToken&resource=$resourceUrl"
32.
33.     $Authorization = Invoke-RestMethod https://login.microsoftonline.com/common/oauth2/token `
34.       -Method Post -ContentType "application/x-www-form-urlencoded" `
35.       -Body $refreshBody `
36.       -UseBasicParsing
37.   }
38.   Catch {
39.     $webResponse = $_.Exception.Response
40.   }
41.
42.   If ($webResponse -ne $null) {
43.     # Get Authorization code
44.     GraphAPIGetAuthCode.ps1 -ClientId $clientId -ClientSecret $clientSecret -RedirectUrl $redirectUrl   
45.
46.     $authCode = get-content $PSScriptRoot"\authCode.txt"
47.     $body = "grant_type=authorization_code&redirect_uri=$redirectUrl&client_id=$clientId&client_secret=$clientSecretEncoded&code=$authCode&resource=$resourceUrl"
48.
49.     $Authorization = Invoke-RestMethod https://login.microsoftonline.com/common/oauth2/token `
50.       -Method Post -ContentType "application/x-www-form-urlencoded" `
51.       -Body $body `
52.       -UseBasicParsing
53.   }
54.
55.   # Store refreshToken
56.   Set-Content $PSScriptRoot"\refreshToken.txt" $Authorization.refresh_token
57.
58.   # Store accessToken
59.   $accessToken = $Authorization.access_token
60.   Set-Content $PSScriptRoot"\accessToken.txt" $accessToken
61. } 

Getting actual date with Invoke-RestMethod from Graph

After all is done we can interact with Graph as followed:

1.  Invoke-RestMethod -Headers @{Authorization = "Bearer $accessToken"} `
2.                    -Uri  https://graph.microsoft.com/v1.0/me `
3.                    -Method Get

You can download the scripts here: https://github.com/ruudmens/SysAdminScripts/tree/master/Graph