Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New command: m365 entra multitenant get. Closes #6007 #6029

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const dictionary = [
'member',
'messaging',
'model',
'multitenant',
'm365',
'news',
'oauth2',
Expand Down
94 changes: 94 additions & 0 deletions docs/docs/cmd/entra/multitenant/multitenant-get.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@

import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# entra multitenant get

Gets properties of the multitenant organization

## Usage

```sh
m365 entra multitenant get [options]
```

## Options

<Global />

## Remarks

:::info

To use this command you must be at least **Security Administrator**.

:::

## Examples

Gets properties of the multitenant organization

```sh
m365 entra multitenant get
```

## Response

<Tabs>
<TabItem value="JSON">

```json
{
"id": "c231d4a5-138f-4bdf-9fee-f26a90ea3ad0",
"createdDateTime": "2024-05-05T05:05:05Z",
"state": "active",
"displayName": "Contoso organization",
"description": "Multitenant organization between Contoso, Fabrikam, and Woodgrove Bank"
}
```

</TabItem>
<TabItem value="Text">

```text
createdDateTime: 2024-05-05T05:05:05Z
description : Multitenant organization between Contoso, Fabrikam, and Woodgrove Bank
displayName : Contoso organization
id : c231d4a5-138f-4bdf-9fee-f26a90ea3ad0
state : active
```

</TabItem>
<TabItem value="CSV">

```csv
id,createdDateTime,state,displayName,description
c231d4a5-138f-4bdf-9fee-f26a90ea3ad0,2024-05-05T05:05:05Z,active,Contoso organization,"Multitenant organization between Contoso, Fabrikam, and Woodgrove Bank"
```

</TabItem>
<TabItem value="Markdown">

```md
# entra multitenant get

Date: 5/5/2024

## Contoso organization (c231d4a5-138f-4bdf-9fee-f26a90ea3ad0)

Property | Value
---------|-------
id | c231d4a5-138f-4bdf-9fee-f26a90ea3ad0
createdDateTime | 2024-05-05T05:05:05Z
state | active
displayName | Contoso organization
description | Multitenant organization between Contoso, Fabrikam, and Woodgrove Bank
```

</TabItem>
</Tabs>

## More information

- Multitenant organization: https://learn.microsoft.com/entra/identity/multi-tenant-organizations/overview
9 changes: 9 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,15 @@ const sidebars: SidebarsConfig = {
}
]
},
{
multitenant: [
{
type: 'doc',
label: 'multitenant get',
id: 'cmd/entra/multitenant/multitenant-get'
}
]
},
{
m365group: [
{
Expand Down
1 change: 1 addition & 0 deletions src/m365/entra/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export default {
M365GROUP_USER_LIST: `${prefix} m365group user list`,
M365GROUP_USER_REMOVE: `${prefix} m365group user remove`,
M365GROUP_USER_SET: `${prefix} m365group user set`,
MULTITENANT_GET: `${prefix} multitenant get`,
OAUTH2GRANT_ADD: `${prefix} oauth2grant add`,
OAUTH2GRANT_LIST: `${prefix} oauth2grant list`,
OAUTH2GRANT_REMOVE: `${prefix} oauth2grant remove`,
Expand Down
93 changes: 93 additions & 0 deletions src/m365/entra/commands/multitenant/multitenant-get.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import request from '../../../../request.js';
import commands from '../../commands.js';
import { telemetry } from '../../../../telemetry.js';
import { pid } from '../../../../utils/pid.js';
import { session } from '../../../../utils/session.js';
import { Logger } from '../../../../cli/Logger.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import command from './multitenant-get.js';
import { CommandError } from '../../../../Command.js';

describe(commands.MULTITENANT_GET, () => {
let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
const response = {
"id": "ab217953-e37f-4691-97b8-dbb8a0a3bcaf",
"createdDateTime": "2024-05-05T05:05:05",
"state": "active",
"displayName": "Contoso organization",
"description": "Contoso and partners"
};

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;
});

after(() => {
sinon.restore();
auth.connection.active = false;
});

it('has correct name', () => {
assert.strictEqual(command.name, commands.MULTITENANT_GET);
});

it('has a description', () => {
assert.notStrictEqual(command.description, null);
});

it('retrieves information about the multitenant organization', async () => {
sinon.stub(request, 'get').callsFake(async (opts) => {
if (opts.url === 'https://graph.microsoft.com/v1.0/tenantRelationships/multiTenantOrganization') {
return response;
}

throw 'Invalid request';
});

await command.action(logger, { options: { } });
assert(loggerLogSpy.calledOnceWithExactly(response));
});

it('handles random API error', async () => {
const errorMessage = 'Something went wrong';
sinon.stub(request, 'get').rejects(new Error(errorMessage));

await assert.rejects(command.action(logger, { options: {} }), new CommandError(errorMessage));
});
});
44 changes: 44 additions & 0 deletions src/m365/entra/commands/multitenant/multitenant-get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { Logger } from '../../../../cli/Logger.js';
import request, { CliRequestOptions } from '../../../../request.js';
import GraphCommand from '../../../base/GraphCommand.js';
import commands from '../../commands.js';

interface MultitenantOrganization {
createdDateTime?: string;
displayName?: string;
description?: string;
id?: string;
state?: string;
}

class EntraMultitenantGetCommand extends GraphCommand {
public get name(): string {
return commands.MULTITENANT_GET;
}

public get description(): string {
return 'Gets properties of the multitenant organization';
}

public async commandAction(logger: Logger): Promise<void> {

const requestOptions: CliRequestOptions = {
url: `${this.resource}/v1.0/tenantRelationships/multiTenantOrganization`,
headers: {
accept: 'application/json;odata.metadata=none'
},
responseType: 'json'
};

try {
const multitenantOrg = await request.get<MultitenantOrganization>(requestOptions);

await logger.log(multitenantOrg);
}
catch (err: any) {
this.handleRejectedODataJsonPromise(err);
}
}
}

export default new EntraMultitenantGetCommand();