A step by step guide to registering a custom Azure application for interactive MSGraph PowerShell. The example will create an app for use with the Show-Win32AppUI tool.

Why use a custom app?

The Microsoft Graph enables access to a wide scope of Azure / Microsoft 365 providers and resources. A compromised Global Administrator account or errant script could cause widespread damage very quickly.

A custom Azure application can limit MS Graph access to specific requirements of a PowerShell script, reducing the risk.

Disable user consent

The first step is to prevent users granting application consent. User consent is enabled by default and presents a risk of unwanted access to company data.

In the Azure AD portal, navigate to Enterprise applications and then Consent and permissions.

Many companies change the setting to Do not allow user consent. Note that this does create an admin overhead, so you could look into the advanced options of defining low-risk permissions or using conditional access.

User consent

The following admin roles can then grant application consent:

  • Cloud App Administrators
  • Global Administrators

Clean-up Microsoft Graph PowerShell

If you want to implement Custom Apps for access to MSGraph, you should first review and remove excess permissions from the Microsoft Graph PowerShell app. Over time administrators may have consented to more and more permissions.

It isn’t possible to remove permissions or revoke consent in the admin portal, but it does provide the PowerShell commands.

In the Azure AD portal, navigate to Enterprise applications
In the All applications view, select Microsoft Graph PowerShell and then Permissions
Click Review Permissions

User consent

Select This application has more permissions that I want. The following PowerShell is displayed (uses the AzureAD module):

Connect-AzureAD

# Get Service Principal using objectId
$sp = Get-AzureADServicePrincipal -ObjectId "1aded007-dfd1-49cc-8b70-9923a4f53a05"

# Get all delegated permissions for the service principal
$spOAuth2PermissionsGrants = Get-AzureADOAuth2PermissionGrant -All $true| Where-Object { $_.clientId -eq $sp.ObjectId }

# Remove all delegated permissions
$spOAuth2PermissionsGrants | ForEach-Object {
    Remove-AzureADOAuth2PermissionGrant -ObjectId $_.ObjectId
}

# Get all application permissions for the service principal
$spApplicationPermissions = Get-AzureADServiceAppRoleAssignedTo -ObjectId $sp.ObjectId -All $true | Where-Object { $_.PrincipalType -eq "ServicePrincipal" }

# Remove all delegated permissions
$spApplicationPermissions | ForEach-Object {
    Remove-AzureADServiceAppRoleAssignment -ObjectId $_.PrincipalId -AppRoleAssignmentId $_.objectId
}

Custom app Step by Step

The following steps create a new application with delegated API access to MSGraph, suitable for use from a PowerShell script. The permissions are specific to the Show-Win32AppUI

Open the Azure AD portal and select App registrations

Click on New Registration to start the process

New registration

Enter a name for the application and select the single tenant option. Do not enter a redirect URI at this stage.

App Name

Click on Register

The application is created and the admin center shows the Overview page.

Click Add a Redirect URI

App Name

The authentication step is displayed. Click on Add a platform

App Name

Select Mobile and desktop applications

App Name

Enable the nativeclient URI to support PowerShell 5.1 scripts. Add a custom redirect URI of http://localhost to support PowerShell 7.x scripts.

App Name

Click Configure to save the URIs

Now back on the Authentication page, ensure the following options are set:

  • Supported account types = Accounts in this organizational directory only
  • Allow public client flows = No

App Name

Click API permissions in the left pane

User.Read delegated access is already assigned by default. Click Add a permission

App Name

Select the Microsoft Graph API

App Name

Select Delegated permissions

App Name

Search for each of the following delegated permissions, enable and click Add permissions

  • DeviceManagementApps.ReadWrite.All

App Name

Repeat the process to add permissions for the following:

  • Group.ReadWrite.All
  • GroupMember.ReadWrite.All
  • Directory.AccessAsUser.All

The API permissions page will show the list of added permissions with a warning that consent is not granted.
Click Grant admin consent for

App Name

The warnings will be replaced by a green tick.

Return to the application Overview page and note the Application (client) ID - this will be used to authenticate

Add assignment restrictions

By default anyone in the tenant can access the application (although they need Role permissions to make changes in Azure AD and Intune). This step will limit access to a specific group.

View the Properties page of the app and change Assignment required to Yes

App Name

Next click on Users and groups then add user/group. Select the required Azure AD group and Assign. Only members of this group can authenticate using the app.

App Name

Authenticating using the custom app

Delegated consent uses the intersection of application permissions and user permissions to authorise access. i.e. the authenticated user must have the required permissions as well as the application.

Use interactive authentication to provide credentials with the required role permissions. Interactive auth prompts using the familiar browser page:

App Name

Examples of PowerShell authentication using the app are below:

MSAL.PS authentication

$TenantID = <your tenant ID obtained from the AAD Overview page>
$ClientID = <application ID of the custom app>

$Token = Get-MSALToken -TenantID $TenantID -ClientID $ClientID -Interactive

IntuneWin32App authentication

$TenantID = <your tenant ID obtained from the AAD Overview page>
$ClientID = <application ID of the custom app>

Connect-MSIntuneGraph -TenantID $TenantID -ClientID $ClientID -Interactive

The Connect-MSIntuneGraph command in the IntuneWin32App module creates global variables to store the token for later use:

  • $Global:AuthenticationHeader
  • $Global:AccessToken



This article was originally posted on Write-Verbose.com