A companion post to my previous one. This time using Graph API (or rather the PowerShell Graph cmdlets) rather than PowerShell Azure AD. Get on with the times, Rakhesh. :)
Getting Started
First off connect to your tenant with your admin account:
1 2 3 4 5 6 |
Connect-MgGraph # A browser window opens for you to authenticate. # If this is the first time, you will also get a window asking for consent. # Asssuming all goes well you get the following: Welcome To Microsoft Graph! |
By going through the cmdlets reference of this module I found the cmdlet that will let me view existing permission policies: Get-MgPolicyPermissionGrantPolicy
. Running this gives the following erorr though:
1 |
Get-MgPolicyPermissionGrantPolicy_List1: Insufficient privileges to complete the operation. |
The first time you connect via Connect-MgGraph
it creates a service principal in your tenant called Microsoft Graph PowerShell
(this is under Enterprise Applications). You will see this only has permissions to sign in a user so that’s why we are getting the above error. Here’s a screenshot of the default permissions just after I consent:
I’ll have to add additional permissions for the above cmdlet (and others) to work. How do I figure that out?
Googling on the term “graph permission grant policy” brings us to the Graph API reference page for this. If I want to list policies I need the following:
So let’s get these added to the Service Principal. I’ll add the ReadWrite one too as I want to make new ones later after all:
1 |
Connect-MgGraph -Scopes "Policy.Read.PermissionGrant","Policy.ReadWrite.PermissionGrant" |
Here’s the consent page that you are shown (notice the consent related permissions):
I am doing an org wide consent but you don’t have to. And of course, if your admin account doesn’t have the rights to do these consents you’ll have to get someone who has these rights to do it. Usually a Global Admin or a Privileged Role Admin.
Now the cmdlet works:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Get-MgPolicyPermissionGrantPolicy | ft Id,Description,DisplayName Id Description -- ----------- microsoft-all-application-permissions Includes all application permissions (app roles), for all APIs, for any client application. microsoft-all-application-permissions-verified Includes all application permissions (app roles), for all APIs, for client applications from verified publishers or which were registered in this or… microsoft-application-admin Permissions consentable by Application Administrators. microsoft-company-admin Permissions consentable by Company Administrators. microsoft-user-default-legacy All delegated permissions that do not require admin consent as defined by the developer are consentable by member type users by default. microsoft-user-default-low All low risk permissions are consentable by member type users by default. microsoft-user-default-recommended Permissions consentable based on Microsoft's current recommendations. mytenant-all-delegated-permissions Permissions consentable by Application Administrators (Level 1) mytenant-all-graph-app-permissions-except-a-few Permissions consentable by Application administrator (Level 2) |
Notice my previously created custom policies are visible.
Creating a new app consent policy
Let’s make a new policy that allows specific permissions on the Exchange Online API (not Graph API as before). So, similar steps as before but now with Graph cmdlets.
First I want to find the Service Principal of the Exchange Online API. I know what it’s called from the Portal:
But here’s how I can find it via Graph:
1 2 3 4 5 6 7 8 9 10 11 12 |
Get-MgServicePrincipal -All | ?{ $_.DisplayName -match "Exchange" } Id DisplayName AppId SignInAudience -- ----------- ----- -------------- 0ac3bcc7-3659-44d9-af54-e7f287ea4812 MIP Exchange Solutions - SPO 192644fe-6aac-4786-8d93-775a056aa1de AzureADMultipleOrgs 2c459a9f-5c54-41b4-b951-3dd376431953 MIP Exchange Solutions a150d169-7d37-47dd-9b20-156207b7b02f AzureADMultipleOrgs 2f4d6758-e00b-4037-a933-8b5224f00489 Exchange Office Graph Client for AAD - Noninteractive 765fe668-04e7-42ba-aec0-2c96f1d8b652 AzureADMultipleOrgs 465b1655-5c73-4895-9012-ca1cae24f1e5 MIP Exchange Solutions - Teams 2c220739-d44d-4bf7-ba5f-95cf9fb7f10c AzureADMultipleOrgs 57943d81-ce4c-4a80-ae3f-56ce03c6a8fd Exchange Office Graph Client for AAD - Interactive 6da466b6-1d13-4a2c-97bd-51a99e8d4d74 AzureADMultipleOrgs 7e60c873-8d87-4a38-9ad0-68c1532009a3 Microsoft Exchange Online Protection 00000007-0000-0ff1-ce00-000000000000 AzureADMultipleOrgs 8d3a0769-602e-4272-aa8c-5a4a546310a2 MIP Exchange Solutions - ODB 8adc51cc-7477-49a4-be4e-263946b4d561 AzureADMultipleOrgs fc68b031-70e8-4ce5-96a8-b3756967fece Office 365 Exchange Online 00000002-0000-0ff1-ce00-000000000000 AzureADMultipleOrgs |
So it’s the one with AppId 00000002-0000-0ff1-ce00-000000000000
and Id fc68b031-70e8-4ce5-96a8-b3756967fece
. Let’s find its AppRoles as that’s what we need for application permissions:
1 2 3 4 5 6 7 8 9 10 11 |
(Get-MgServicePrincipal -ServicePrincipalId "fc68b031-70e8-4ce5-96a8-b3756967fece").AppRoles AllowedMemberTypes Description ------------------ ----------- {Application} Allows the app to read the organization and related resources, on behalf of the signed-in user. Related resources include things like subscribed SKUs and tenant branding informa… {Application} Application permission grants permission to move mailboxes between Office365 organizations {Application} Allows the app to read the full set of profile properties, reports, and managers of other users in your organization, on behalf of the signed-in user. {Application} Allows the app to read a basic set of profile properties of other users in your organization on behalf of the signed-in user. This includes display name, first and last name, em… {Application} Allows the app to read user's mailbox settings without a signed-in user. Does not include permission t <snip> |
I need additional fields:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
(Get-MgServicePrincipal -ServicePrincipalId "fc68b031-70e8-4ce5-96a8-b3756967fece").AppRoles | ft Value,Id,DisplayName,Description Value Id DisplayName Description ----- -- ----------- ----------- Organization.Read.All 15f260d6-f874-4366-8672-6b3658c5a09b Organization.Read.All Allows the app to read the organization and related resources, on behalf … Mailbox.Migration f7264778-fba9-422d-8e9e-2675a2c4b513 Move mailboxes between organizations Application permission grants permission to move mailboxes between Office… User.Read.All bf24470f-10c1-436d-8d53-7b997eb473be Read all users' full profiles Allows the app to read the full set of profile properties, reports, and m… User.ReadBasic.All 77e65b5a-ceae-48b3-9490-50a86a038a48 Read all users' basic profiles Allows the app to read a basic set of profile properties of other users i… MailboxSettings.Read d45fa9f8-36e5-4cd2-b601-b063c7cf9ac2 Read all user mailbox settings Allows the app to read user's mailbox settings without a signed-in user. … full_access_as_app dc890d15-9560-4a4c-9b7f-a736ec74ec40 Use Exchange Web Services with full access to all mailboxes Allows the app to have full access via Exchange Web Services to all mailb… Mail.Send b633e1c5-b582-4048-a93e-9f11b44c7e96 Send mail as any user Allows the app to send mail as any user without a signed-in user. Calendars.Read 798ee544-9d2d-430c-a058-570e29e34338 Read calendars in all mailboxes Allows the app to read events of all calendars without a signed-in user. Contacts.Read 089fe4d0-434a-44c5-8827-41ba8a0b17f5 Read contacts in all mailboxes Allows the app to read all contacts in all mailboxes without a signed-in … Mail.Read 810c84a8-4a9e-49e6-bf7d-12d183f40d01 Read mail in all mailboxes Allows the app to read mail in all mailboxes without a signed-in user. Mail.ReadWrite e2a3a72e-5f79-4c64-b1b1-878b674786c9 Read and write mail in all mailboxes Allows the app to create, read, update, and delete mail in all mailboxes … Contacts.ReadWrite 6918b873-d17a-4dc1-b314-35f528134491 Read and write contacts in all mailboxes Allows the app to create, read, update, and delete all contacts in all ma… MailboxSettings.ReadWrite f9156939-25cd-4ba8-abfe-7fabcf003749 Read and write all user mailbox settings Allows the app to create, read, update, and delete user's mailbox setting… Tasks.Read c1b0de0a-1de9-455d-919f-eca451053141 Read user tasks in all mailboxes Allows the app to read user tasks in all mailboxes without a signed-in us… Tasks.ReadWrite 2c6a42ca-0d4d-49ad-bc0e-21222c449a65 Read and write tasks in all mailboxes Allows the app to create, read, update, and delete tasks in all mailboxes… Calendars.ReadWrite.All ef54d2bf-783f-4e0f-bca1-3210c0444d99 Read and write calendars in all mailboxes Allows the app to create, read, update, and delete events of all calendar… Calendars.Read.All 2dfdc6dc-2fa7-4a2c-a922-dbd4f85d17be Read calendars in all mailboxes Allows the app to read events of all R without a signed-in user Place.Read.All 4830e04b-48ac-4de5-bbd9-8aceb58e506b Read all company places Allows the app to read company places (conference rooms and room lists) f… Exchange.ManageAsApp dc50a0fb-09a3-484d-be87-e023b12c6440 Manage Exchange As Application Allows the app to manage the organization's Exchange environment without … |
The permission I am interested in is full_access_as_app
. Its Id is dc890d15-9560-4a4c-9b7f-a736ec74ec40
. Let’s create the app consent policy:
1 2 3 4 |
New-MgPolicyPermissionGrantPolicy ` -Id "mytenant-ews-exchange-app-permissions" ` -Description "Permissions consentable by Application administrator (Exchange)" ` -DisplayName "Only full_access_as_app permissions" |
Then include the grants in it (there’s separate cmdlets for include and exclude):
1 2 3 4 5 |
New-MgPolicyPermissionGrantPolicyInclude ` -PermissionGrantPolicyId "mytenant-ews-exchange-app-permissions" ` -PermissionType "application" ` -ResourceApplication "00000002-0000-0ff1-ce00-000000000000" ` -Permissions "dc890d15-9560-4a4c-9b7f-a736ec74ec40" |
Cool, so that’s done.
Creating the custom role
Now let’s create the custom role to add this to. To keep it simple I am going to make a new one rather than modify an existing one. To create roles I need the following permission added to my Graph consents: RoleManagement.ReadWrite.Directory
1 |
Connect-MgGraph -Scopes "RoleManagement.ReadWrite.Directory" |
I then took a long time figuring out the cmdlet to create custom roles, as it was not very intuitive.
I know the Graph API request to do this but I couldn’t figure out the cmdlet name from the request. There is a New-MgDirectoryRole
cmdlet that looked it might be the one, but it wasn’t. Finally I switched to the Beta profile as I noticed the Graph API request was to the Beta API and then looked around and by trial and error found New-MgRoleManagementDirectoryRoleDefinition
. Here’s how I then created the custom role with the above permissions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# defining the permissions $allowedResourceAction = @( "microsoft.directory/applications/create", "microsoft.directory/servicePrincipals/allProperties/read", "microsoft.directory/servicePrincipals/create", "microsoft.directory/servicePrincipals/managePermissionGrantsForSelf.mytenant-ews-exchange-app-permissions", "microsoft.directory/servicePrincipals/managePermissionGrantsForAll.mytenant-ews-exchange-app-permissions" ) $rolePermissions = @{'allowedResourceActions'= $allowedResourceAction} # Switch to the beta profile for this cmdlet Select-MgProfile -Name beta New-MgRoleManagementDirectoryRoleDefinition ` -DisplayName "Application administrator (Exchange)" ` -Description "Can manage selected Exchange app registrations permissions" ` -IsEnabled:$true ` -RolePermissions $rolePermissions |
Added my user to this custom role, and boom she’s able to grant admin consents:
She cannot, however, do it for any other Exchange Online permissions:
Nice!
Update: Also see this post.