diff --git a/docs/docs/cmd/entra/resourcenamespace/resourcenamespace-list.mdx b/docs/docs/cmd/entra/resourcenamespace/resourcenamespace-list.mdx
new file mode 100644
index 00000000000..cda37a32a79
--- /dev/null
+++ b/docs/docs/cmd/entra/resourcenamespace/resourcenamespace-list.mdx
@@ -0,0 +1,96 @@
+import Global from '/docs/cmd/_global.mdx';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# entra resourcenamespace list
+
+Get a list of the RBAC resource namespaces and their properties
+
+## Usage
+
+```sh
+m365 entra resourcenamespace list [options]
+```
+
+## Options
+
+
+
+## Remarks
+
+:::warning
+
+The command is based on an API that is currently in preview and is subject to change once the API reached general availability.
+
+:::
+
+## Examples
+
+Retrieve all resource namespaces.
+
+```sh
+m365 entra resourcenamespace list
+```
+
+## Response
+
+
+
+
+ ```json
+ [
+ {
+ "id": "microsoft.directory",
+ "name": "microsoft.directory"
+ },
+ {
+ "id": "microsoft.aad.b2c",
+ "name": "microsoft.aad.b2c"
+ }
+ ]
+ ```
+
+
+
+
+ ```text
+ id name
+ -------------------- --------------------
+ microsoft.directory microsoft.directory
+ microsoft.aad.b2c microsoft.aad.b2c
+ ```
+
+
+
+
+ ```csv
+ id,name
+ microsoft.directory,microsoft.directory
+ microsoft.aad.b2c,microsoft.aad.b2c
+ ```
+
+
+
+
+ ```md
+ # entra resourcenamespace list
+
+ Date: 1/31/2025
+
+ ## microsoft.directory (microsoft.directory)
+
+ Property | Value
+ ---------|-------
+ id | microsoft.directory
+ name | microsoft.directory
+
+ ## microsoft.aad.b2c (microsoft.aad.b2c)
+
+ Property | Value
+ ---------|-------
+ id | microsoft.aad.b2c
+ name | microsoft.aad.b2c
+ ```
+
+
+
diff --git a/docs/src/config/sidebars.ts b/docs/src/config/sidebars.ts
index 3e109021e95..928aabbaf0e 100644
--- a/docs/src/config/sidebars.ts
+++ b/docs/src/config/sidebars.ts
@@ -632,6 +632,15 @@ const sidebars: SidebarsConfig = {
}
]
},
+ {
+ resourcenamespace: [
+ {
+ type: 'doc',
+ label: 'resourcenamespace list',
+ id: 'cmd/entra/resourcenamespace/resourcenamespace-list'
+ }
+ ]
+ },
{
roledefinition: [
{
diff --git a/src/config.ts b/src/config.ts
index b9240f96c83..016ee7da291 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -38,6 +38,7 @@ export default {
'https://graph.microsoft.com/Reports.ReadWrite.All',
'https://graph.microsoft.com/RoleAssignmentSchedule.ReadWrite.Directory',
'https://graph.microsoft.com/RoleEligibilitySchedule.Read.Directory',
+ 'https://graph.microsoft.com/RoleManagement.Read.Directory',
'https://graph.microsoft.com/SecurityEvents.Read.All',
'https://graph.microsoft.com/ServiceHealth.Read.All',
'https://graph.microsoft.com/ServiceMessage.Read.All',
diff --git a/src/m365/entra/commands.ts b/src/m365/entra/commands.ts
index 86382e565b6..572747cddd5 100644
--- a/src/m365/entra/commands.ts
+++ b/src/m365/entra/commands.ts
@@ -89,6 +89,7 @@ export default {
PIM_ROLE_ASSIGNMENT_ELIGIBILITY_LIST: `${prefix} pim role assignment eligibility list`,
PIM_ROLE_REQUEST_LIST: `${prefix} pim role request list`,
POLICY_LIST: `${prefix} policy list`,
+ RESOURCENAMESPACE_LIST: `${prefix} resourcenamespace list`,
ROLEDEFINITION_ADD: `${prefix} roledefinition add`,
ROLEDEFINITION_LIST: `${prefix} roledefinition list`,
ROLEDEFINITION_GET: `${prefix} roledefinition get`,
diff --git a/src/m365/entra/commands/resourcenamespace/resourcenamespace-list.spec.ts b/src/m365/entra/commands/resourcenamespace/resourcenamespace-list.spec.ts
new file mode 100644
index 00000000000..698803500f4
--- /dev/null
+++ b/src/m365/entra/commands/resourcenamespace/resourcenamespace-list.spec.ts
@@ -0,0 +1,118 @@
+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 './resourcenamespace-list.js';
+
+
+describe(commands.RESOURCENAMESPACE_LIST, () => {
+ let log: string[];
+ let logger: Logger;
+ let loggerLogSpy: sinon.SinonSpy;
+
+ 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;
+ });
+
+ beforeEach(() => {
+ log = [];
+ logger = {
+ log: async (msg: string) => {
+ log.push(msg);
+ },
+ logRaw: async (msg: string) => {
+ log.push(msg);
+ },
+ logToStderr: async (msg: string) => {
+ log.push(msg);
+ }
+ };
+ loggerLogSpy = sinon.spy(logger, 'log');
+ });
+
+ afterEach(() => {
+ sinonUtil.restore([
+ request.get
+ ]);
+ });
+
+ after(() => {
+ sinon.restore();
+ auth.connection.active = false;
+ });
+
+ it('has correct name', () => {
+ assert.strictEqual(command.name, commands.RESOURCENAMESPACE_LIST);
+ });
+
+ it('has a description', () => {
+ assert.notStrictEqual(command.description, null);
+ });
+
+ it('defines correct properties for the default output', () => {
+ assert.deepStrictEqual(command.defaultProperties(), ['id', 'name']);
+ });
+
+ it(`should get a list of resource namespaces`, async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/beta/roleManagement/directory/resourceNamespaces`) {
+ return {
+ value: [
+ {
+ "id": "microsoft.directory",
+ "name": "microsoft.directory"
+ },
+ {
+ "id": "microsoft.aad.b2c",
+ "name": "microsoft.aad.b2c"
+ }
+ ]
+ };
+ }
+
+ throw 'Invalid request';
+ });
+
+ await command.action(logger, {
+ options: { verbose: true }
+ });
+
+ assert(
+ loggerLogSpy.calledWith([
+ {
+ "id": "microsoft.directory",
+ "name": "microsoft.directory"
+ },
+ {
+ "id": "microsoft.aad.b2c",
+ "name": "microsoft.aad.b2c"
+ }
+ ])
+ );
+ });
+
+ it('handles error when retrieving a list of resource namespaces failed', async () => {
+ sinon.stub(request, 'get').callsFake(async (opts) => {
+ if (opts.url === `https://graph.microsoft.com/beta/roleManagement/directory/resourceNamespaces`) {
+ throw { error: { message: 'An error has occurred' } };
+ }
+ throw `Invalid request`;
+ });
+
+ await assert.rejects(
+ command.action(logger, { options: {} } as any),
+ new CommandError('An error has occurred')
+ );
+ });
+});
\ No newline at end of file
diff --git a/src/m365/entra/commands/resourcenamespace/resourcenamespace-list.ts b/src/m365/entra/commands/resourcenamespace/resourcenamespace-list.ts
new file mode 100644
index 00000000000..c9dbda151f8
--- /dev/null
+++ b/src/m365/entra/commands/resourcenamespace/resourcenamespace-list.ts
@@ -0,0 +1,34 @@
+import { Logger } from '../../../../cli/Logger.js';
+import { odata } from '../../../../utils/odata.js';
+import GraphCommand from '../../../base/GraphCommand.js';
+import commands from '../../commands.js';
+
+class ResourceNamespaceListCommand extends GraphCommand {
+ public get name(): string {
+ return commands.RESOURCENAMESPACE_LIST;
+ }
+
+ public get description(): string {
+ return 'Get a list of the RBAC resource namespaces and their properties';
+ }
+
+ public defaultProperties(): string[] | undefined {
+ return ['id', 'name'];
+ }
+
+ public async commandAction(logger: Logger): Promise {
+ if (this.verbose) {
+ await logger.logToStderr('Getting a list of the RBAC resource namespaces and their properties...');
+ }
+
+ try {
+ const results = await odata.getAllItems<{ id: string, name: string }>(`${this.resource}/beta/roleManagement/directory/resourceNamespaces`);
+ await logger.log(results);
+ }
+ catch (err: any) {
+ this.handleRejectedODataJsonPromise(err);
+ }
+ }
+}
+
+export default new ResourceNamespaceListCommand();
\ No newline at end of file