Using PowerShell to Connect to Microsoft Graph API

Update 6.29.2018: Changes have been make to the functionality of the well-known ClientIDs that are referred to in this article. Further information can be found here, along with guidance on how to create your own Native application which could be configured to have similar functionality to the well-known ClientIDs.

Introduction

In this article I will show you how to connect to Microsoft Graph and query for all users in Azure AD. With Microsoft Graph, you can only return between 1 and 999 objects, per query. If your Azure AD object count is greater than 999, you will need to construct a loop that will capture the next set(s) of users using the .nextlink approach.

Pre-requisites

The easy way is to use the PowerShell Gallery to install the Azure module.

 Install-Package Azure

Setup

Creating the AuthToken a Function

While creating a function is by no means required, it will make your life easier.

Its important to note that the $resourceAppIdURI is for graph.microsoft.com instead of graph.windows.net. using Graph.microsoft.com will direct you to Microsoft Graph where as Graph.windows.net will direct you to Azure AD Graph API. As outlined by the Microsoft Azure team, their efforts are concentrated on Microsoft Graph. While there are scenarios that Azure AD Graph may be approperiate, my efforts (at least in this article) will be focused on Microsoft Graph.

 Function GetAuthToken
    {
    param
        (
        [Parameter(Mandatory=$true)]
        $TenantName
        )
    Import-Module Azure
    $clientId = "1950a258-227b-4e31-a9cf-717495945fc2" 
    $redirectUri = "urn:ietf:wg:oauth:2.0:oob"
    $resourceAppIdURI = "https://graph.microsoft.com"
    $authority = "https://login.microsoftonline.com/$TenantName"
    $authContext = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext" -ArgumentList $authority
    $Credential = Get-Credential
    $AADCredential = New-Object "Microsoft.IdentityModel.Clients.ActiveDirectory.UserCredential" -ArgumentList $credential.UserName,$credential.Password
    $authResult = $authContext.AcquireToken($resourceAppIdURI, $clientId,$AADCredential)
    return $authResult
    }

Creating the GetAllObjectOfType Function

One of the challenges with Microsoft Graph is that it doesn't inherently have a process to capture every object in Azure AD like Get-MSOLuser does. Because of this, we have to construct a batch process that will create the initial URI. Once that is constructed and executed, we have to capture the "nextlink" to create a call that will allow us to query the next batch of the data set until there is nothing left to query. If you were to run this function without the Do-Until, you would return the initial batch set (default 100 objects) and halt processing.

 Function GetAllObjectOfType
    {
    param
        (
        [Parameter(Mandatory=$true)]
        $Tenant,
        [Parameter(Mandatory=$true)]
        $Type,
        [Parameter(Mandatory=$false)]
        $BatchSize,
        [Parameter(Mandatory=$false)]
        $Version
        )
  
    if($BatchSize -eq $null) {$BatchSize=100}
    if($Version -eq $null) {$Version='Beta'}
    #------Get the authorization token------#
    $token = GetAuthToken -TenantName $tenant 
  
    #------Building Rest Api header with authorization token------#
    $authHeader = @{
        'Content-Type'='application\json'
        'Authorization'=$token.CreateAuthorizationHeader()
        }

    #------Initial URI Construction------#
    $uri = "https://graph.microsoft.com/$Version/$type`?top=$BatchSize"
    $ObjCapture= @()
    do{
        $users = Invoke-RestMethod -Uri $uri –Headers $authHeader –Method Get
        $FoundUsers = ($Users.value).count
        write-host "URI" $uri " | Found:" $FoundUsers
        #------Batched URI Construction------#
        $uri = $users.'@odata.nextlink'
        $ObjCapture = $ObjCapture + $users.value
       
    }until ($uri -eq $null)
    $ObjCapture
}

Execution

To output all 'user' types run the following cmdlet. -Tenant should be the tenant name, -type should be the type of object you are trying to return. -Version will default to "beta" based off the script that was laid out above. I've been playing around with beta lately because there is a more flexible data set. Version could also be v1.0, however the URI constructor cannot have "`?top=$BatchSize" in it in order for it to run successfully.

 GetAllObjectOfType -Tenant "cloudlojik.onmicrosoft.com" -Type "Users" -BatchSize 80 | fl

In this case, when I execute the script, it outputs all of the users in my tenant

 PS C:\> C:\Graph.ps1
cmdlet Get-Credential at command pipeline position 1
Supply values for the following parameters:
URI https://graph.microsoft.com/Beta/Users?top=80  | Found: 80

id                             : 41cb16c4-fea6-4b78-ac78-aa67b33da8a5
deletedDateTime                : 
accountEnabled                 : True
assignedLicenses               : {}
assignedPlans                  : {}
businessPhones                 : {}
city                           : 
companyName                    : 
country                        : 
department                     : 
deviceKeys                     : {}
displayName                    : AADConnect SyncAcct
employeeId                     : 
givenName                      : AADConnect
jobTitle                       : 
mail                           : 
mailNickname                   : aadconnectsync
mobilePhone                    : 
onPremisesDomainName           : 
onPremisesImmutableId          : 
onPremisesLastSyncDateTime     : 
onPremisesProvisioningErrors   : {}
onPremisesSecurityIdentifier   : 
onPremisesSamAccountName       : 
onPremisesSyncEnabled          : 
onPremisesUserPrincipalName    : 
passwordPolicies               : None
passwordProfile                : 
officeLocation                 : 
postalCode                     : 
preferredDataLocation          : 
preferredLanguage              : 
provisionedPlans               : {}
proxyAddresses                 : {}
refreshTokensValidFromDateTime : 2017-09-05T22:43:36Z
showInAddressList              : 
imAddresses                    : {}
state                          : 
streetAddress                  : 
surname                        : SyncAcct
usageLocation                  : US
userPrincipalName              : aadconnectsync@cloudlojik.onmicrosoft.com
userType                       : Member

Connect to Microsoft Graph and Query All (users) - Sample Script: ConnectToMicrosoftGraph