Skip to content

Instantly share code, notes, and snippets.

@JustinGrote
Created April 14, 2021 16:59
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JustinGrote/3929dbc67e84a6c95f53e34a2dd17ac0 to your computer and use it in GitHub Desktop.
Save JustinGrote/3929dbc67e84a6c95f53e34a2dd17ac0 to your computer and use it in GitHub Desktop.
Azure Function Powershell to fetch users from a customer tenant via Microsoft Graph
using namespace System.Net
# Input bindings are passed in via param block.
[CmdletBinding()]
param(
[HttpRequestContext]$Request,
[HashTable]$TriggerMetadata
)
$ErrorActionPreference = 'Stop'
#PropertiesToReturn
$userProperties = @(
'UserPrincipalName'
'GivenName'
'SurName'
'DisplayName'
'Mail'
'OfficeLocation'
'StreetAddress'
'City'
'State'
'PostalCode'
'JobTitle'
'Department'
'BusinessPhones'
'MobilePhone'
'UserType'
'EmployeeId'
)
function Get-MgAccessToken {
[CmdletBinding()]
param(
$tenantId = $ENV:TENANTID,
$appId = $ENV:APPID,
$appSecret = $ENV:APPSECRET
)
$getTokenParams = @{
Uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
Method = 'POST'
Body = @{
Grant_Type = 'client_credentials'
Scope = 'https://graph.microsoft.com/.default'
Client_Id = $ENV:APPID
Client_Secret = $ENV:APPSECRET
}
}
(Invoke-RestMethod @getTokenParams -ErrorAction Stop).access_token
}
try {
$customer = $TriggerMetaData.customer
$filter = $TriggerMetaData.filter
if (-not $customer) {
throw 'You must specify a customer domain either as a guid or a domain. Example: /api/GetAzureAdUsersForAditaas?customer=adslt.onmicrosoft.com'
}
$connectResult = Connect-MgGraph -AccessToken (Get-MgAccessToken -Verbose -TenantId $customer)
if ($connectResult -ne 'Welcome To Microsoft Graph!') {
throw "Could not connect to Microsoft Graph: $PSItem"
}
$getMgUserParams = @{
Property = $userProperties
PageSize = 999
All = $true
ErrorAction = 'Stop'
}
if ($filter) {
$getMGUserParams.Filter = $filter
$getMgUserParams.ConsistencyLevel = 'Eventual'
}
$userResult = Get-MgUser @getMgUserParams
| Select-Object -Property $userProperties
# Associate values to output bindings by calling 'Push-OutputBinding'.
Write-Verbose "$($userResult.count) users returned for tenant $customer"
Push-OutputBinding -Name Response -Value (
[HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $userResult
}
)
} catch {
if ([String]$PSItem -match 'The identity of the calling application could not be established') {
[String]$Message = "The application is not provisioned for customer $customer. Please have the customer " +
'perform admin consent by clicking the following link while logged in as a user that has rights to perform ' +
"admin consent: https://login.microsoftonline.com/$customer/adminconsent?client_id=$($ENV:APPID). Error: $PSItem"
}
if (-not $Message) { $Message = $PSItem }
#TODO: Guidance if tenant is not set up yet
Push-OutputBinding -Name Response -Value (
[HttpResponseContext]@{
StatusCode = [HttpStatusCode]::BadRequest
Body = [String]$Message
}
)
}
@JustinGrote
Copy link
Author

To use this in an azure function you must provide the APPID, TenantId of your app, and app client secret of an app registration in your tenant. You must give it User.Read API permissions:
image

And your customers must adopt the app into their environment using the Admin Consent workflow. I recommend the URL method:
https://docs.microsoft.com/en-us/azure/active-directory/manage-apps/grant-admin-consent#construct-the-url-for-granting-tenant-wide-admin-consent

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment