From e1ec7eada4484cb7c0e7928cda4566d59b7357d2 Mon Sep 17 00:00:00 2001 From: Nico De Cleyre Date: Sun, 3 Nov 2024 19:47:41 +0100 Subject: [PATCH] First commit --- .../cmd/spo/web/web-roleassignment-add.mdx | 18 ++- .../cmd/spo/web/web-roleassignment-remove.mdx | 18 ++- .../web/web-roleassignment-add.spec.ts | 121 +++++++++++++++++- .../commands/web/web-roleassignment-add.ts | 41 +++++- .../web/web-roleassignment-remove.spec.ts | 118 ++++++++++++++++- .../commands/web/web-roleassignment-remove.ts | 41 +++++- 6 files changed, 339 insertions(+), 18 deletions(-) diff --git a/docs/docs/cmd/spo/web/web-roleassignment-add.mdx b/docs/docs/cmd/spo/web/web-roleassignment-add.mdx index f0ea2984156..e3798db54d8 100644 --- a/docs/docs/cmd/spo/web/web-roleassignment-add.mdx +++ b/docs/docs/cmd/spo/web/web-roleassignment-add.mdx @@ -17,13 +17,19 @@ m365 spo web roleassignment add [options] : URL of the site. `--principalId [principalId]` -: SharePoint ID of principal it may be either user id or group id we want to add permissions to. Specify either `principalId`, `upn`, or `groupName` but not multiple. +: SharePoint ID of principal it may be either user id or group id we want to add permissions to. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. `--upn [upn]` -: The upn/email of user to assign role to. Specify either `principalId`, `upn`, or `groupName` but not multiple. +: The upn/email of user to assign role to. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. `--groupName [groupName]` -: The group name of the SharePoint group Specify either `principalId`, `upn`, or `groupName` but not multiple. +: The group name of the SharePoint group. Use this option exclusively for SharePoint Online groups. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. + +`--entraGroupId [entraGroupId]` +: ID of the Microsoft Entra group to add. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. + +`--entraGroupName [entraGroupName]` +: Display name of the Microsoft Entra group to add. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. `--roleDefinitionId [roleDefinitionId]` : ID of role definition. Specify either `roleDefinitionId` or `roleDefinitionName` but not both. @@ -60,6 +66,12 @@ add role assignment to a site for principal id _11_ and role definition name _Fu m365 spo web roleassignment add --webUrl "https://contoso.sharepoint.com/sites/project-x" --principalId 11 --roleDefinitionName "Full Control" ``` +add role assignment using a Entra Group ID and a role definition + +```sh +m365 spo web roleassignment add --webUrl "https://contoso.sharepoint.com/sites/project-x" --entraGroupId '27ae47f1-48f1-46f3-980b-d3c1470e398d' --roleDefinitionId 1073741829 +``` + ## Response The command won't return a response on success. diff --git a/docs/docs/cmd/spo/web/web-roleassignment-remove.mdx b/docs/docs/cmd/spo/web/web-roleassignment-remove.mdx index eea2c6c7036..cfc3b5e810f 100644 --- a/docs/docs/cmd/spo/web/web-roleassignment-remove.mdx +++ b/docs/docs/cmd/spo/web/web-roleassignment-remove.mdx @@ -17,13 +17,19 @@ m365 spo web roleassignment remove [options] : URL of the site. `--principalId [principalId]` -: SharePoint ID of principal it may be either user id or group id we want to add permissions to. Specify either `principalId`, `upn`, or `groupName` but not multiple. +: SharePoint ID of principal it may be either user id or group id we want to add permissions to. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. `--upn [upn]` -: The upn/email of user to assign role to. Specify either `principalId`, `upn`, or `groupName` but not multiple. +: The upn/email of user to assign role to. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. `--groupName [groupName]` -: The group name of the SharePoint group Specify either `principalId`, `upn`, or `groupName` but not multiple. +: The group name of the SharePoint group. Use this option exclusively for SharePoint Online groups. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. + +`--entraGroupId [entraGroupId]` +: ID of the Microsoft Entra group to remove. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. + +`--entraGroupName [entraGroupName]` +: Display name of the Microsoft Entra group to remove. Specify either `principalId`, `upn`, `groupName`, `entraGroupId` or `entraGroupName` but not multiple. `-f, --force` : Don't prompt for confirming removing the roleassignment. @@ -57,6 +63,12 @@ Remove roleassignment from web based on principal Id without prompting for confi m365 spo web roleassignment remove --webUrl "https://contoso.sharepoint.com/sites/contoso-sales" --principalId 2 --force ``` +Remove roleassignment from web based on Entra Group Id + +```sh +m365 spo web roleassignment remove --webUrl "https://contoso.sharepoint.com/sites/contoso-sales" --entraGroupId '27ae47f1-48f1-46f3-980b-d3c1470e398d' --force +``` + ## Response The command won't return a response on success. diff --git a/src/m365/spo/commands/web/web-roleassignment-add.spec.ts b/src/m365/spo/commands/web/web-roleassignment-add.spec.ts index a10cf309f09..2e31530cc2f 100644 --- a/src/m365/spo/commands/web/web-roleassignment-add.spec.ts +++ b/src/m365/spo/commands/web/web-roleassignment-add.spec.ts @@ -15,6 +15,65 @@ import spoGroupGetCommand from '../group/group-get.js'; import spoRoleDefinitionListCommand from '../roledefinition/roledefinition-list.js'; import spoUserGetCommand from '../user/user-get.js'; import command from './web-roleassignment-add.js'; +import { entraGroup } from '../../../../utils/entraGroup.js'; +import { spo } from '../../../../utils/spo.js'; + +const graphGroup = { + id: '27ae47f1-48f1-46f3-980b-d3c1470e398d', + deletedDateTime: null, + classification: null, + createdDateTime: '2024-03-22T20:18:37Z', + creationOptions: [], + description: null, + displayName: 'Marketing', + expirationDateTime: null, + groupTypes: [ + 'Unified' + ], + isAssignableToRole: null, + mail: 'Marketing@contoso.onmicrosoft.com', + mailEnabled: true, + mailNickname: 'Marketing', + membershipRule: null, + membershipRuleProcessingState: null, + onPremisesDomainName: null, + onPremisesLastSyncDateTime: null, + onPremisesNetBiosName: null, + onPremisesSamAccountName: null, + onPremisesSecurityIdentifier: null, + onPremisesSyncEnabled: null, + preferredDataLocation: null, + preferredLanguage: null, + proxyAddresses: [ + 'SPO:SPO_de7704ba-415d-4dd0-9bbd-fa565007a87e@SPO_18c58817-3bc9-489d-ac63-f7264fb357e5', + 'SMTP:Marketing@contoso.onmicrosoft.com' + ], + renewedDateTime: '2024-03-22T20:18:37Z', + resourceBehaviorOptions: [], + resourceProvisioningOptions: [], + securityEnabled: true, + securityIdentifier: 'S-1-12-1-665733105-1190349041-3268610968-2369326662', + theme: null, + uniqueName: null, + visibility: 'Private', + onPremisesProvisioningErrors: [], + serviceProvisioningErrors: [] +}; + +const entraGroupResponse = { + Id: 11, + IsHiddenInUI: false, + LoginName: 'c:0o.c|federateddirectoryclaimprovider|27ae47f1-48f1-46f3-980b-d3c1470e398d', + Title: 'Marketing members', + PrincipalType: 1, + Email: '', + Expiration: '', + IsEmailAuthenticationGuestUser: false, + IsShareByEmailGuestUser: false, + IsSiteAdmin: false, + UserId: null, + UserPrincipalName: null +}; describe(commands.WEB_ROLEASSIGNMENT_ADD, () => { let log: any[]; @@ -48,7 +107,10 @@ describe(commands.WEB_ROLEASSIGNMENT_ADD, () => { afterEach(() => { sinonUtil.restore([ request.post, - cli.executeCommandWithOutput + cli.executeCommandWithOutput, + entraGroup.getGroupById, + entraGroup.getGroupByDisplayName, + spo.ensureEntraGroup ]); }); @@ -95,6 +157,17 @@ describe(commands.WEB_ROLEASSIGNMENT_ADD, () => { assert.strictEqual(actual, true); }); + + it('fails validation if the entaGroupId is not a valid guid', async () => { + const actual = await command.validate({ options: { webUrl: 'https://contoso.sharepoint.com', entraGroupId: 'invalid', roleDefinitionId: '1073741827' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('passes validation if the entaGroupId is a valid guid', async () => { + const actual = await command.validate({ options: { webUrl: 'https://contoso.sharepoint.com', entraGroupId: '27ae47f1-48f1-46f3-980b-d3c1470e398d', roleDefinitionId: 1073741827 } }, commandInfo); + assert.strictEqual(actual, true); + }); + it('add role assignment on web by role definition id', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf('_api/web/roleassignments/addroleassignment(principalid=\'11\',roledefid=\'1073741827\')') > -1) { @@ -257,6 +330,52 @@ describe(commands.WEB_ROLEASSIGNMENT_ADD, () => { }); }); + it('adds role assignment on web by role definition id and Entra group ID', async () => { + sinon.stub(entraGroup, 'getGroupById').withArgs(graphGroup.id).resolves(graphGroup); + sinon.stub(spo, 'ensureEntraGroup').withArgs('https://contoso.sharepoint.com', graphGroup).resolves(entraGroupResponse); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf('_api/web/roleassignments/addroleassignment(principalid=\'11\',roledefid=\'1073741827\')') > -1) { + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { + options: { + debug: true, + webUrl: 'https://contoso.sharepoint.com', + entraGroupId: '27ae47f1-48f1-46f3-980b-d3c1470e398d', + principalId: 11, + roleDefinitionId: 1073741827 + } + }); + }); + + it('adds role assignment on web by role definition id and Entra group name', async () => { + sinon.stub(entraGroup, 'getGroupByDisplayName').withArgs(graphGroup.displayName).resolves(graphGroup); + sinon.stub(spo, 'ensureEntraGroup').withArgs('https://contoso.sharepoint.com', graphGroup).resolves(entraGroupResponse); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf('_api/web/roleassignments/addroleassignment(principalid=\'11\',roledefid=\'1073741827\')') > -1) { + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { + options: { + debug: true, + webUrl: 'https://contoso.sharepoint.com', + entraGroupName: 'Marketing', + principalId: 11, + roleDefinitionId: 1073741827 + } + }); + }); + it('correctly handles error when role definition does not exist', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf('/_api/web/roleassignments/addroleassignment(principalid=\'11\',roledefid=\'1073741827\')') > -1) { diff --git a/src/m365/spo/commands/web/web-roleassignment-add.ts b/src/m365/spo/commands/web/web-roleassignment-add.ts index 6e9978d488b..4b9742f47df 100644 --- a/src/m365/spo/commands/web/web-roleassignment-add.ts +++ b/src/m365/spo/commands/web/web-roleassignment-add.ts @@ -1,3 +1,4 @@ +import { Group } from '@microsoft/microsoft-graph-types'; import { cli, CommandOutput } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; import Command from '../../../../Command.js'; @@ -10,6 +11,8 @@ import spoGroupGetCommand, { Options as SpoGroupGetCommandOptions } from '../gro import spoRoleDefinitionListCommand, { Options as SpoRoleDefinitionListCommandOptions } from '../roledefinition/roledefinition-list.js'; import { RoleDefinition } from '../roledefinition/RoleDefinition.js'; import spoUserGetCommand, { Options as SpoUserGetCommandOptions } from '../user/user-get.js'; +import { entraGroup } from '../../../../utils/entraGroup.js'; +import { spo } from '../../../../utils/spo.js'; interface CommandArgs { options: Options; @@ -20,6 +23,8 @@ interface Options extends GlobalOptions { principalId?: number; upn?: string; groupName?: string; + entraGroupId?: string; + entraGroupName?: string; roleDefinitionId?: number; roleDefinitionName?: string; } @@ -48,6 +53,8 @@ class SpoWebRoleAssignmentAddCommand extends SpoCommand { principalId: typeof args.options.principalId !== 'undefined', upn: typeof args.options.upn !== 'undefined', groupName: typeof args.options.groupName !== 'undefined', + entraGroupId: typeof args.options.entraGroupId !== 'undefined', + entraGroupName: typeof args.options.entraGroupName !== 'undefined', roleDefinitionId: typeof args.options.roleDefinitionId !== 'undefined', roleDefinitionName: typeof args.options.roleDefinitionName !== 'undefined' }); @@ -68,6 +75,12 @@ class SpoWebRoleAssignmentAddCommand extends SpoCommand { { option: '--groupName [groupName]' }, + { + option: '--entraGroupId [entraGroupId]' + }, + { + option: '--entraGroupName [entraGroupName]' + }, { option: '--roleDefinitionId [roleDefinitionId]' }, @@ -93,6 +106,10 @@ class SpoWebRoleAssignmentAddCommand extends SpoCommand { return `Specified roleDefinitionId ${args.options.roleDefinitionId} is not a number`; } + if (args.options.entraGroupId && !validation.isValidGuid(args.options.entraGroupId)) { + return `'${args.options.entraGroupId}' is not a valid GUID for option entraGroupId.`; + } + return true; } ); @@ -100,7 +117,7 @@ class SpoWebRoleAssignmentAddCommand extends SpoCommand { #initOptionSets(): void { this.optionSets.push( - { options: ['principalId', 'upn', 'groupName'] }, + { options: ['principalId', 'upn', 'groupName', 'entraGroupId', 'entraGroupName'] }, { options: ['roleDefinitionId', 'roleDefinitionName'] } ); } @@ -115,15 +132,29 @@ class SpoWebRoleAssignmentAddCommand extends SpoCommand { if (args.options.upn) { args.options.principalId = await this.getUserPrincipalId(args.options); - await this.addRoleAssignment(logger, args.options); } else if (args.options.groupName) { args.options.principalId = await this.getGroupPrincipalId(args.options); - await this.addRoleAssignment(logger, args.options); } - else { - await this.addRoleAssignment(logger, args.options); + else if (args.options.entraGroupId || args.options.entraGroupName) { + if (this.verbose) { + await logger.logToStderr('Retrieving group information...'); + } + + let group: Group; + if (args.options.entraGroupId) { + group = await entraGroup.getGroupById(args.options.entraGroupId); + } + else { + group = await entraGroup.getGroupByDisplayName(args.options.entraGroupName!); + } + + const siteUser = await spo.ensureEntraGroup(args.options.webUrl, group); + args.options.principalId = siteUser.Id; } + + await this.addRoleAssignment(logger, args.options); + } catch (err: any) { this.handleRejectedODataJsonPromise(err); diff --git a/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts b/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts index 3073576e3d0..2941921c02a 100644 --- a/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts +++ b/src/m365/spo/commands/web/web-roleassignment-remove.spec.ts @@ -14,6 +14,65 @@ import commands from '../../commands.js'; import spoGroupGetCommand from '../group/group-get.js'; import spoUserGetCommand from '../user/user-get.js'; import command from './web-roleassignment-remove.js'; +import { entraGroup } from '../../../../utils/entraGroup.js'; +import { spo } from '../../../../utils/spo.js'; + +const graphGroup = { + id: '27ae47f1-48f1-46f3-980b-d3c1470e398d', + deletedDateTime: null, + classification: null, + createdDateTime: '2024-03-22T20:18:37Z', + creationOptions: [], + description: null, + displayName: 'Marketing', + expirationDateTime: null, + groupTypes: [ + 'Unified' + ], + isAssignableToRole: null, + mail: 'Marketing@contoso.onmicrosoft.com', + mailEnabled: true, + mailNickname: 'Marketing', + membershipRule: null, + membershipRuleProcessingState: null, + onPremisesDomainName: null, + onPremisesLastSyncDateTime: null, + onPremisesNetBiosName: null, + onPremisesSamAccountName: null, + onPremisesSecurityIdentifier: null, + onPremisesSyncEnabled: null, + preferredDataLocation: null, + preferredLanguage: null, + proxyAddresses: [ + 'SPO:SPO_de7704ba-415d-4dd0-9bbd-fa565007a87e@SPO_18c58817-3bc9-489d-ac63-f7264fb357e5', + 'SMTP:Marketing@contoso.onmicrosoft.com' + ], + renewedDateTime: '2024-03-22T20:18:37Z', + resourceBehaviorOptions: [], + resourceProvisioningOptions: [], + securityEnabled: true, + securityIdentifier: 'S-1-12-1-665733105-1190349041-3268610968-2369326662', + theme: null, + uniqueName: null, + visibility: 'Private', + onPremisesProvisioningErrors: [], + serviceProvisioningErrors: [] +}; + +const entraGroupResponse = { + Id: 11, + IsHiddenInUI: false, + LoginName: 'c:0o.c|federateddirectoryclaimprovider|27ae47f1-48f1-46f3-980b-d3c1470e398d', + Title: 'Marketing members', + PrincipalType: 1, + Email: '', + Expiration: '', + IsEmailAuthenticationGuestUser: false, + IsShareByEmailGuestUser: false, + IsSiteAdmin: false, + UserId: null, + UserPrincipalName: null +}; describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { let log: any[]; @@ -57,7 +116,10 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { sinonUtil.restore([ request.post, cli.executeCommandWithOutput, - cli.promptForConfirmation + cli.promptForConfirmation, + entraGroup.getGroupById, + entraGroup.getGroupByDisplayName, + spo.ensureEntraGroup ]); }); @@ -94,6 +156,16 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { assert.strictEqual(actual, true); }); + it('fails validation if the entreGroupId option is not a valid guid', async () => { + const actual = await command.validate({ options: { webUrl: 'https://contoso.sharepoint.com', entraGroupId: 'invalid' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('passes validation if the entreGroupId option is a valid guid', async () => { + const actual = await command.validate({ options: { webUrl: 'https://contoso.sharepoint.com', entraGroupId: 'a449d6a5-1a05-4e79-b345-e2519fd66a99' } }, commandInfo); + assert.strictEqual(actual, true); + }); + it('remove role assignment from web', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if ((opts.url as string).indexOf('_api/web/roleassignments/removeroleassignment(principalid=\'11\')') > -1) { @@ -280,4 +352,48 @@ describe(commands.WEB_ROLEASSIGNMENT_REMOVE, () => { } }); }); + + it('removes role assignment from web using entraGroupId', async () => { + sinon.stub(entraGroup, 'getGroupById').withArgs(graphGroup.id).resolves(graphGroup); + sinon.stub(spo, 'ensureEntraGroup').withArgs('https://contoso.sharepoint.com', graphGroup).resolves(entraGroupResponse); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf('_api/web/roleassignments/removeroleassignment(principalid=\'11\')') > -1) { + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { + options: { + debug: true, + webUrl: 'https://contoso.sharepoint.com', + entraGroupId: '27ae47f1-48f1-46f3-980b-d3c1470e398d', + force: true + } + }); + }); + + it('removes role assignment from web using entraGroupName', async () => { + sinon.stub(entraGroup, 'getGroupByDisplayName').withArgs(graphGroup.displayName).resolves(graphGroup); + sinon.stub(spo, 'ensureEntraGroup').withArgs('https://contoso.sharepoint.com', graphGroup).resolves(entraGroupResponse); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf('_api/web/roleassignments/removeroleassignment(principalid=\'11\')') > -1) { + return; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { + options: { + debug: true, + webUrl: 'https://contoso.sharepoint.com', + entraGroupName: 'Marketing', + force: true + } + }); + }); }); diff --git a/src/m365/spo/commands/web/web-roleassignment-remove.ts b/src/m365/spo/commands/web/web-roleassignment-remove.ts index 06212312c08..0ad54775ad6 100644 --- a/src/m365/spo/commands/web/web-roleassignment-remove.ts +++ b/src/m365/spo/commands/web/web-roleassignment-remove.ts @@ -1,3 +1,4 @@ +import { Group } from '@microsoft/microsoft-graph-types'; import { cli, CommandOutput } from '../../../../cli/cli.js'; import { Logger } from '../../../../cli/Logger.js'; import Command from '../../../../Command.js'; @@ -8,6 +9,8 @@ import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; import spoGroupGetCommand, { Options as SpoGroupGetCommandOptions } from '../group/group-get.js'; import spoUserGetCommand, { Options as SpoUserGetCommandOptions } from '../user/user-get.js'; +import { entraGroup } from '../../../../utils/entraGroup.js'; +import { spo } from '../../../../utils/spo.js'; interface CommandArgs { options: Options; @@ -18,6 +21,8 @@ interface Options extends GlobalOptions { principalId?: number; upn?: string; groupName?: string; + entraGroupId?: string; + entraGroupName?: string; force?: boolean; } @@ -45,6 +50,8 @@ class SpoWebRoleAssignmentRemoveCommand extends SpoCommand { principalId: typeof args.options.principalId !== 'undefined', upn: typeof args.options.upn !== 'undefined', groupName: typeof args.options.groupName !== 'undefined', + entraGroupId: typeof args.options.entraGroupId !== 'undefined', + entraGroupName: typeof args.options.entraGroupName !== 'undefined', force: (!(!args.options.force)).toString() }); }); @@ -64,6 +71,12 @@ class SpoWebRoleAssignmentRemoveCommand extends SpoCommand { { option: '--groupName [groupName]' }, + { + option: '--entraGroupId [entraGroupId]' + }, + { + option: '--entraGroupName [entraGroupName]' + }, { option: '-f, --force' } @@ -82,6 +95,10 @@ class SpoWebRoleAssignmentRemoveCommand extends SpoCommand { return `Specified principalId ${args.options.principalId} is not a number`; } + if (args.options.entraGroupId && !validation.isValidGuid(args.options.entraGroupId)) { + return `'${args.options.entraGroupId}' is not a valid GUID for option entraGroupId.`; + } + return true; } ); @@ -89,7 +106,7 @@ class SpoWebRoleAssignmentRemoveCommand extends SpoCommand { #initOptionSets(): void { this.optionSets.push( - { options: ['principalId', 'upn', 'groupName'] } + { options: ['principalId', 'upn', 'groupName', 'entraGroupId', 'entraGroupName'] } ); } @@ -114,15 +131,29 @@ class SpoWebRoleAssignmentRemoveCommand extends SpoCommand { try { if (options.upn) { options.principalId = await this.getUserPrincipalId(options); - await this.removeRoleAssignmentWithOptions(logger, options); } else if (options.groupName) { options.principalId = await this.getGroupPrincipalId(options); - await this.removeRoleAssignmentWithOptions(logger, options); } - else { - await this.removeRoleAssignmentWithOptions(logger, options); + else if (options.entraGroupId || options.entraGroupName) { + if (this.verbose) { + await logger.logToStderr('Retrieving group information...'); + } + + let group: Group; + if (options.entraGroupId) { + group = await entraGroup.getGroupById(options.entraGroupId); + } + else { + group = await entraGroup.getGroupByDisplayName(options.entraGroupName!); + } + + const siteUser = await spo.ensureEntraGroup(options.webUrl, group); + options.principalId = siteUser.Id; } + + await this.removeRoleAssignmentWithOptions(logger, options); + } catch (err: any) { this.handleRejectedODataJsonPromise(err);