diff --git a/docs/docs/cmd/viva/engage/engage-community-user-remove.mdx b/docs/docs/cmd/viva/engage/engage-community-user-remove.mdx
new file mode 100644
index 0000000000..9d95a95fc8
--- /dev/null
+++ b/docs/docs/cmd/viva/engage/engage-community-user-remove.mdx
@@ -0,0 +1,55 @@
+import Global from '/docs/cmd/_global.mdx';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# viva engage community user remove
+
+Removes a specified user from a Microsoft 365 Viva Engage community
+
+## Usage
+
+```sh
+m365 viva engage community user remove [options]
+```
+
+## Options
+
+```md definition-list
+`-i, --communityId [communityId]`
+: The ID of the Viva Engage community. Specify `communityId`, `communityDisplayName` or `entraGroupId`.
+
+`-n, --communityDisplayName [communityDisplayName]`
+: The display name of the Viva Engage community. Specify `communityId`, `communityDisplayName` or `entraGroupId`.
+
+`--entraGroupId [entraGroupId]`
+: The ID of the Microsoft 365 group. Specify `communityId`, `communityDisplayName` or `entraGroupId`.
+
+`--id [id]`
+: Microsoft Entra ID of the user. Specify either `id` or `userName` but not both.
+
+`--userName [userName]`
+: The user principal name of the user. Specify either `id` or `userName` but not both.
+
+`-f, --force`
+: Don't prompt for confirming removing the user from the specified Viva Engage community.
+```
+
+
+
+## Examples
+
+Remove a user specified by ID as a member from a community specified by display name.
+
+```sh
+m365 viva engage community user remove --communityDisplayName "All company" --id 098b9f52-f48c-4401-819f-29c33794c3f5
+```
+
+Remove a user specified by UPN from a community specified by its group ID without confirmation.
+
+```sh
+m365 viva engage community user remove --entraGroupId a03c0c35-ef9a-419b-8cab-f89e0a8d2d2a --userName john.doe@contoso.com --force
+```
+
+## Response
+
+The command won't return a response on success.
diff --git a/docs/src/config/sidebars.ts b/docs/src/config/sidebars.ts
index 929281df70..5c6072a3b1 100644
--- a/docs/src/config/sidebars.ts
+++ b/docs/src/config/sidebars.ts
@@ -4475,6 +4475,11 @@ const sidebars: SidebarsConfig = {
label: 'engage community list',
id: 'cmd/viva/engage/engage-community-list'
},
+ {
+ type: 'doc',
+ label: 'engage community user remove',
+ id: 'cmd/viva/engage/engage-community-user-remove'
+ },
{
type: 'doc',
label: 'engage group list',
diff --git a/src/m365/viva/commands/engage/Community.ts b/src/m365/viva/commands/engage/Community.ts
index ed5df59649..75f5405227 100644
--- a/src/m365/viva/commands/engage/Community.ts
+++ b/src/m365/viva/commands/engage/Community.ts
@@ -3,4 +3,5 @@ export interface Community {
displayName: string;
description?: string;
privacy: string;
+ groupId: string;
}
\ No newline at end of file
diff --git a/src/m365/viva/commands/engage/engage-community-user-remove.spec.ts b/src/m365/viva/commands/engage/engage-community-user-remove.spec.ts
new file mode 100644
index 0000000000..2db76a5762
--- /dev/null
+++ b/src/m365/viva/commands/engage/engage-community-user-remove.spec.ts
@@ -0,0 +1,239 @@
+
+import assert from 'assert';
+import sinon from 'sinon';
+import auth from '../../../../Auth.js';
+import { Logger } from '../../../../cli/Logger.js';
+import { CommandError } from '../../../../Command.js';
+import request from '../../../../request.js';
+import { telemetry } from '../../../../telemetry.js';
+import { pid } from '../../../../utils/pid.js';
+import { session } from '../../../../utils/session.js';
+import { sinonUtil } from '../../../../utils/sinonUtil.js';
+import commands from '../../commands.js';
+import command from './engage-community-user-remove.js';
+import { CommandInfo } from '../../../../cli/CommandInfo.js';
+import { z } from 'zod';
+import { cli } from '../../../../cli/cli.js';
+import { vivaEngage } from '../../../../utils/vivaEngage.js';
+import { entraUser } from '../../../../utils/entraUser.js';
+
+describe(commands.ENGAGE_COMMUNITY_USER_REMOVE, () => {
+ const communityId = 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiIzNjAyMDAxMTAwOSJ9';
+ const communityDisplayName = 'All company';
+ const entraGroupId = 'b6c35b51-ebca-445c-885a-63a67d24cb53';
+ const userName = 'john@contoso.com';
+ const userId = '3f2504e0-4f89-11d3-9a0c-0305e82c3301';
+
+ let log: string[];
+ let logger: Logger;
+ let commandInfo: CommandInfo;
+ let commandOptionsSchema: z.ZodTypeAny;
+
+ before(() => {
+ sinon.stub(auth, 'restoreAuth').resolves();
+ sinon.stub(telemetry, 'trackEvent').returns();
+ sinon.stub(pid, 'getProcessName').returns('');
+ sinon.stub(session, 'getId').returns('');
+ auth.connection.active = true;
+ commandInfo = cli.getCommandInfo(command);
+ commandOptionsSchema = commandInfo.command.getSchemaToParse()!;
+ sinon.stub(entraUser, 'getUserIdByUpn').resolves(userId);
+ sinon.stub(vivaEngage, 'getEntraGroupIdByCommunityDisplayName').resolves(entraGroupId);
+ sinon.stub(vivaEngage, 'getEntraGroupIdByCommunityId').resolves(entraGroupId);
+ });
+
+ beforeEach(() => {
+ log = [];
+ logger = {
+ log: async (msg: string) => {
+ log.push(msg);
+ },
+ logRaw: async (msg: string) => {
+ log.push(msg);
+ },
+ logToStderr: async (msg: string) => {
+ log.push(msg);
+ }
+ };
+ });
+
+ afterEach(() => {
+ sinonUtil.restore([
+ request.delete,
+ cli.promptForConfirmation
+ ]);
+ });
+
+ after(() => {
+ sinon.restore();
+ auth.connection.active = false;
+ });
+
+ it('has correct name', () => {
+ assert.strictEqual(command.name, commands.ENGAGE_COMMUNITY_USER_REMOVE);
+ });
+
+ it('has a description', () => {
+ assert.notStrictEqual(command.description, null);
+ });
+
+ it('fails validation if entraGroupId is not a valid GUID', () => {
+ const actual = commandOptionsSchema.safeParse({
+ entraGroupId: 'invalid',
+ userName: userName
+ });
+ assert.notStrictEqual(actual.success, true);
+ });
+
+ it('fails validation if id is not a valid GUID', () => {
+ const actual = commandOptionsSchema.safeParse({
+ entraGroupId: entraGroupId,
+ id: 'invalid'
+ });
+ assert.notStrictEqual(actual.success, true);
+ });
+
+ it('fails validation if userName is invalid user principal name', () => {
+ const actual = commandOptionsSchema.safeParse({
+ entraGroupId: entraGroupId,
+ userName: 'invalid'
+ });
+ assert.notStrictEqual(actual.success, true);
+ });
+
+ it('fails validation if communityId, communityDisplayName or entraGroupId are not specified', () => {
+ const actual = commandOptionsSchema.safeParse({});
+ assert.notStrictEqual(actual.success, true);
+ });
+
+ it('fails validation if communityId, communityDisplayName and entraGroupId are specified', () => {
+ const actual = commandOptionsSchema.safeParse({
+ communityId: communityId,
+ communityDisplayName: communityDisplayName,
+ entraGroupId: entraGroupId,
+ id: userId
+ });
+ assert.notStrictEqual(actual.success, true);
+ });
+
+ it('passes validation if communityId is specified', () => {
+ const actual = commandOptionsSchema.safeParse({
+ communityId: communityId,
+ userName: userName
+ });
+ assert.strictEqual(actual.success, true);
+ });
+
+ it('passes validation if entraGroupId is specified with a proper GUID', () => {
+ const actual = commandOptionsSchema.safeParse({
+ entraGroupId: entraGroupId,
+ userName: userName
+ });
+ assert.strictEqual(actual.success, true);
+ });
+
+ it('passes validation if communityDisplayName is specified', () => {
+ const actual = commandOptionsSchema.safeParse({
+ communityDisplayName: communityDisplayName,
+ userName: userName
+ });
+ assert.strictEqual(actual.success, true);
+ });
+
+ it('correctly removes user specified by id', async () => {
+ const deleteStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/owners/${userId}/$ref`) {
+ return;
+ }
+
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/members/${userId}/$ref`) {
+ return;
+ }
+
+ throw 'Invalid request';
+ });
+
+ await command.action(logger, { options: { communityDisplayName: communityDisplayName, id: userId, force: true, verbose: true } });
+ assert(deleteStub.calledTwice);
+ });
+
+ it('correctly removes user by userName', async () => {
+ const deleteStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/owners/${userId}/$ref`) {
+ return;
+ }
+
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/members/${userId}/$ref`) {
+ return;
+ }
+ throw 'Invalid request';
+ });
+
+ await command.action(logger, { options: { communityId: communityId, verbose: true, userName: userName, force: true } });
+ assert(deleteStub.calledTwice);
+ });
+
+ it('correctly removes user as member by userName', async () => {
+ const deleteStub = sinon.stub(request, 'delete').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/owners/${userId}/$ref`) {
+ throw {
+ response: {
+ status: 404,
+ data: {
+ message: 'Object does not exist...'
+ }
+ }
+ };
+ }
+
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/members/${userId}/$ref`) {
+ return;
+ }
+ throw 'Invalid request';
+ });
+
+ sinonUtil.restore(cli.promptForConfirmation);
+ sinon.stub(cli, 'promptForConfirmation').resolves(true);
+
+ await command.action(logger, { options: { communityId: communityId, verbose: true, userName: userName } });
+ assert(deleteStub.calledTwice);
+ });
+
+ it('handles API error when removing user', async () => {
+ const errorMessage = 'Invalid object identifier';
+ sinon.stub(request, 'delete').callsFake(async opts => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/groups/${entraGroupId}/owners/${userId}/$ref`) {
+ throw {
+ response: {
+ status: 400,
+ data: { error: { 'odata.error': { message: { value: errorMessage } } } }
+ }
+ };
+ }
+
+ throw 'Invalid request';
+ });
+
+ sinonUtil.restore(cli.promptForConfirmation);
+ sinon.stub(cli, 'promptForConfirmation').resolves(true);
+
+ await assert.rejects(command.action(logger, { options: { entraGroupId: entraGroupId, id: userId } }),
+ new CommandError(errorMessage));
+ });
+
+ it('prompts before removal when confirmation argument not passed', async () => {
+ const promptStub: sinon.SinonStub = sinon.stub(cli, 'promptForConfirmation').resolves(false);
+
+ await command.action(logger, { options: { entraGroupId: entraGroupId, id: userId } });
+
+ assert(promptStub.called);
+ });
+
+ it('aborts execution when prompt not confirmed', async () => {
+ const deleteStub = sinon.stub(request, 'delete');
+ sinon.stub(cli, 'promptForConfirmation').resolves(false);
+
+ await command.action(logger, { options: { entraGroupId: entraGroupId, id: userId } });
+ assert(deleteStub.notCalled);
+ });
+});
\ No newline at end of file
diff --git a/src/m365/viva/commands/engage/engage-community-user-remove.ts b/src/m365/viva/commands/engage/engage-community-user-remove.ts
index 1a989f070e..a0de421306 100644
--- a/src/m365/viva/commands/engage/engage-community-user-remove.ts
+++ b/src/m365/viva/commands/engage/engage-community-user-remove.ts
@@ -8,7 +8,6 @@ import { validation } from '../../../../utils/validation.js';
import { vivaEngage } from '../../../../utils/vivaEngage.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { entraUser } from '../../../../utils/entraUser.js';
-import { formatting } from '../../../../utils/formatting.js';
import { cli } from '../../../../cli/cli.js';
const options = globalOptionsZod
@@ -43,7 +42,7 @@ class VivaEngageCommunityUserRemoveCommand extends GraphCommand {
}
public get description(): string {
- return 'Lists all users within a specified Microsoft 365 Viva Engage community';
+ return 'Removes a specified user from a Microsoft 365 Viva Engage community';
}
public get schema(): z.ZodTypeAny {
@@ -69,7 +68,7 @@ class VivaEngageCommunityUserRemoveCommand extends GraphCommand {
public async commandAction(logger: Logger, args: CommandArgs): Promise {
try {
if (args.options.force) {
-
+ await this.deleteUserFromCommunity(args.options, logger);
}
else {
const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove the user ${args.options.id || args.options.userName} from the community ${args.options.communityDisplayName || args.options.communityId || args.options.entraGroupId}?` });
@@ -88,6 +87,38 @@ class VivaEngageCommunityUserRemoveCommand extends GraphCommand {
if (this.verbose) {
await logger.logToStderr('Removing user from community...');
}
+
+ let entraGroupId = options.entraGroupId;
+
+ if (options.communityDisplayName) {
+ entraGroupId = await vivaEngage.getEntraGroupIdByCommunityDisplayName(options.communityDisplayName);
+ }
+ else if (options.communityId) {
+ entraGroupId = await vivaEngage.getEntraGroupIdByCommunityId(options.communityId);
+ }
+
+ const userId = options.id || await entraUser.getUserIdByUpn(options.userName!);
+
+ await this.deleteUser(entraGroupId!, userId, 'owners');
+ await this.deleteUser(entraGroupId!, userId, 'members');
+ }
+
+ private async deleteUser(entraGroupId: string, userId: string, role: string): Promise {
+ try {
+ const requestOptions: CliRequestOptions = {
+ url: `${this.resource}/v1.0/groups/${entraGroupId}/${role}/${userId}/$ref`,
+ headers: {
+ accept: 'application/json;odata.metadata=none'
+ },
+ responseType: 'json'
+ };
+ await request.delete(requestOptions);
+ }
+ catch (err: any) {
+ if (err.response.status !== 404) {
+ throw err.response.data;
+ }
+ }
}
}
diff --git a/src/utils/vivaEngage.spec.ts b/src/utils/vivaEngage.spec.ts
new file mode 100644
index 0000000000..baf42f2aed
--- /dev/null
+++ b/src/utils/vivaEngage.spec.ts
@@ -0,0 +1,187 @@
+import assert from 'assert';
+import sinon from 'sinon';
+import { cli } from '../cli/cli.js';
+import request from '../request.js';
+import { sinonUtil } from './sinonUtil.js';
+import { vivaEngage } from './vivaEngage.js';
+import { formatting } from './formatting.js';
+import { settingsNames } from '../settingsNames.js';
+
+describe('utils/vivaEngage', () => {
+ const displayName = 'All Company';
+ const invalidDisplayName = 'All Compayn';
+ const entraGroupId = '0bed8b86-5026-4a93-ac7d-56750cc099f1';
+ const communityId = 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9';
+ const communityResponse = {
+ "id": "eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9",
+ "description": "This is the default group for everyone in the network",
+ "displayName": "All Company",
+ "privacy": "Public",
+ "groupId": "0bed8b86-5026-4a93-ac7d-56750cc099f1"
+ };
+ const anotherCommunityResponse = {
+ "id": "eyJfdHlwZ0NzY5SIwiIiSJ9IwO6IaWQiOIMTM1ODikdyb3Vw",
+ "description": "Test only",
+ "displayName": "All Company",
+ "privacy": "Private",
+ "groupId": "0bed8b86-5026-4a93-ac7d-56750cc099f1"
+ };
+
+ afterEach(() => {
+ sinonUtil.restore([
+ request.get,
+ cli.getSettingWithDefaultValue,
+ cli.handleMultipleResultsFound
+ ]);
+ });
+
+ it('correctly get single community id by name using getCommunityIdByDisplayName', async () => {
+ sinon.stub(request, 'get').callsFake(async opts => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
+ return {
+ value: [
+ communityResponse
+ ]
+ };
+ }
+
+ return 'Invalid Request';
+ });
+
+ const actual = await vivaEngage.getCommunityIdByDisplayName(displayName);
+ assert.deepStrictEqual(actual, 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9');
+ });
+
+ it('handles selecting single community when multiple communities with the specified name found using getCommunityIdByDisplayName and cli is set to prompt', async () => {
+ sinon.stub(request, 'get').callsFake(async opts => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
+ return {
+ value: [
+ communityResponse,
+ anotherCommunityResponse
+ ]
+ };
+ }
+
+ return 'Invalid Request';
+ });
+
+ sinon.stub(cli, 'handleMultipleResultsFound').resolves(communityResponse);
+
+ const actual = await vivaEngage.getCommunityIdByDisplayName(displayName);
+ assert.deepStrictEqual(actual, 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9');
+ });
+
+ it('throws error message when no community was found using getCommunityIdByDisplayName', async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(invalidDisplayName)}'`) {
+ return { value: [] };
+ }
+
+ throw 'Invalid Request';
+ });
+
+ await assert.rejects(vivaEngage.getCommunityIdByDisplayName(invalidDisplayName)), Error(`The specified Viva Engage community '${invalidDisplayName}' does not exist.`);
+ });
+
+ it('throws error message when multiple communities were found using getCommunityIdByDisplayName', async () => {
+ sinon.stub(cli, 'getSettingWithDefaultValue').callsFake((settingName, defaultValue) => {
+ if (settingName === settingsNames.prompt) {
+ return false;
+ }
+
+ return defaultValue;
+ });
+
+ sinon.stub(request, 'get').callsFake(async opts => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
+ return {
+ value: [
+ communityResponse,
+ anotherCommunityResponse
+ ]
+ };
+ }
+
+ return 'Invalid Request';
+ });
+
+ await assert.rejects(vivaEngage.getCommunityIdByDisplayName(displayName),
+ Error(`Multiple Viva Engage communities with name '${displayName}' found. Found: ${communityResponse.id}, ${anotherCommunityResponse.id}.`));
+ });
+
+ it('correctly get single community id by group id using getCommunityIdByEntraGroupId', async () => {
+ sinon.stub(request, 'get').callsFake(async opts => {
+ if (opts.url === 'https://graph.microsoft.com/v1.0/employeeExperience/communities?$select=id,groupId') {
+ return {
+ value: [
+ communityResponse
+ ]
+ };
+ }
+
+ return 'Invalid Request';
+ });
+
+ const actual = await vivaEngage.getCommunityIdByEntraGroupId(entraGroupId);
+ assert.deepStrictEqual(actual, 'eyJfdHlwZSI6Ikdyb3VwIiwiaWQiOiI0NzY5MTM1ODIwOSJ9');
+ });
+
+ it('throws error message when no community was found using getCommunityIdByEntraGroupId', async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === 'https://graph.microsoft.com/v1.0/employeeExperience/communities?$select=id,groupId') {
+ return { value: [] };
+ }
+
+ throw 'Invalid Request';
+ });
+
+ await assert.rejects(vivaEngage.getCommunityIdByEntraGroupId(entraGroupId)), Error(`The Microsoft Entra group with id '${entraGroupId}' is not associated with any Viva Engage community.`);
+ });
+
+ it('correctly gets Entra group ID by community ID using getEntraGroupIdByCommunityId', async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}?$select=groupId`) {
+ return communityResponse;
+ }
+
+ throw 'Invalid Request';
+ });
+
+ const actual = await vivaEngage.getEntraGroupIdByCommunityId(communityId);
+ assert.deepStrictEqual(actual, '0bed8b86-5026-4a93-ac7d-56750cc099f1');
+ });
+
+ it('throws error message when no Entra group ID was found using getEntraGroupIdByCommunityId', async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}?$select=groupId`) {
+ return null;
+ }
+
+ throw 'Invalid Request';
+ });
+
+ await assert.rejects(vivaEngage.getEntraGroupIdByCommunityId(communityId)), Error(`The specified Viva Engage community with ID '${communityId}' does not exist.`);
+ });
+
+ it('correctly gets Entra group ID by community display name using getEntraGroupIdByCommunityDisplayName', async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}?$select=groupId`) {
+ return communityResponse;
+ }
+
+ if (opts.url === `https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`) {
+ return {
+ value: [
+ communityResponse
+ ]
+ };
+ }
+
+ throw 'Invalid Request';
+ });
+
+ const actual = await vivaEngage.getEntraGroupIdByCommunityDisplayName(displayName);
+ assert.deepStrictEqual(actual, entraGroupId);
+ });
+});
\ No newline at end of file
diff --git a/src/utils/vivaEngage.ts b/src/utils/vivaEngage.ts
new file mode 100644
index 0000000000..9fc4403a01
--- /dev/null
+++ b/src/utils/vivaEngage.ts
@@ -0,0 +1,79 @@
+import { cli } from '../cli/cli.js';
+import { Community } from '../m365/viva/commands/engage/Community.js';
+import request, { CliRequestOptions } from '../request.js';
+import { formatting } from './formatting.js';
+import { odata } from './odata.js';
+
+export const vivaEngage = {
+ /**
+ * Get Viva Engage community ID by display name.
+ * @param displayName Community display name.
+ * @returns The ID of the Viva Engage community.
+ */
+ async getCommunityIdByDisplayName(displayName: string): Promise {
+ const communities = await odata.getAllItems(`https://graph.microsoft.com/v1.0/employeeExperience/communities?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`);
+
+ if (communities.length === 0) {
+ throw `The specified Viva Engage community '${displayName}' does not exist.`;
+ }
+
+ if (communities.length > 1) {
+ const resultAsKeyValuePair = formatting.convertArrayToHashTable('id', communities);
+ const selectedCommunity = await cli.handleMultipleResultsFound(`Multiple Viva Engage communities with name '${displayName}' found.`, resultAsKeyValuePair);
+ return selectedCommunity.id;
+ }
+
+ return communities[0].id;
+ },
+
+ /**
+ * Get Viva Engage community ID by Microsoft Entra group ID.
+ * Note: The Graph API doesn't support filtering by groupId, so we need to retrieve all communities and filter them in memory.
+ * @param entraGroupId The ID of the Microsoft Entra group.
+ * @returns The ID of the Viva Engage community.
+ */
+ async getCommunityIdByEntraGroupId(entraGroupId: string): Promise {
+ const communities = await odata.getAllItems('https://graph.microsoft.com/v1.0/employeeExperience/communities?$select=id,groupId');
+
+ const filtereCommunities = communities.filter(c => c.groupId === entraGroupId);
+
+ if (filtereCommunities.length === 0) {
+ throw `The Microsoft Entra group with id '${entraGroupId}' is not associated with any Viva Engage community.`;
+ }
+
+ return filtereCommunities[0].id;
+ },
+
+ /**
+ * Get Viva Engage group ID by community ID.
+ * @param communityId The ID of the Viva Engage community.
+ * @returns The ID of the Viva Engage group.
+ */
+ async getEntraGroupIdByCommunityId(communityId: string): Promise {
+ const requestOptions: CliRequestOptions = {
+ url: `https://graph.microsoft.com/v1.0/employeeExperience/communities/${communityId}?$select=groupId`,
+ headers: {
+ accept: 'application/json;odata.metadata=none'
+ },
+ responseType: 'json'
+ };
+
+ const community = await request.get(requestOptions);
+
+ if (!community) {
+ throw `The specified Viva Engage community with ID '${communityId}' does not exist.`;
+ }
+
+ return community.groupId;
+ },
+
+ /**
+ * Get Viva Engage group ID by community display name.
+ * @param displayName Community display name.
+ * @returns The ID of the Viva Engage group.
+ */
+ async getEntraGroupIdByCommunityDisplayName(displayName: string): Promise {
+ const communityId = await this.getCommunityIdByDisplayName(displayName);
+ return await this.getEntraGroupIdByCommunityId(communityId);
+ }
+};
\ No newline at end of file