Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions docs/docs/cmd/pp/website/website-webrole-list.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import Global from '../../_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# pp website webrole list

Lists all webroles for the specified Power Pages website.

## Usage

```sh
m365 pp website webrole list [options]
```

## Options

```md definition-list
`--websiteId [websiteId]`
: ID of the Power Pages website. Specify either `websiteId` or `websiteName` but not both.

`--websiteName [websiteName]`
: The unique name (not the display name) of the Power Pages website. Specify either `websiteId` or `websiteName` but not both.

`-e, --environmentName <environmentName>`
: The name of the environment where the Power Pages websites are located.

`--asAdmin`
: Run the command as admin and retrieve Power Pages websites for environments you do not have explicitly assigned permissions to.
```

<Global />

## Permissions

<Tabs>
<TabItem value="Delegated">

| Resource | Permissions |
|--------------------|--------------------------|
| Power Platform API | PowerPages.Websites.Read |
| Dynamics CRM | user_impersonation |

</TabItem>
</Tabs>

## Examples

List all webroles for the site by name.

```sh
m365 pp website webrole list --websiteName "Contoso" --environmentName "Default-2ca3eaa5-140f-4175-8261-3272edf9f339"
```

List all webroles for the site by name as admin.

```sh
m365 pp website webrole list --websiteName "Contoso" --environmentName "Default-2ca3eaa5-140f-4175-8261-3272edf9f339" --asAdmin
```

List all webroles for the site by id.

```sh
m365 pp website webrole list --websiteId "2ca3eaa5-140f-4175-8261-3272edf9f339" --environmentName "Default-2ca3eaa5-140f-4175-8261-3272edf9f339"
```

List all webroles for the site by id as admin.

```sh
m365 pp website webrole list --websiteId "2ca3eaa5-140f-4175-8261-3272edf9f339" --environmentName "Default-2ca3eaa5-140f-4175-8261-3272edf9f339" --asAdmin
```

## Response

<Tabs>
<TabItem value="JSON">

```json
[
{
"mspp_webroleid": "a242a363-6077-4cb7-b2d1-1714502d129a",
"mspp_name": "Anonymous Users",
"mspp_description": "Role for anonymous users",
"mspp_key": null,
"mspp_authenticatedusersrole": false,
"mspp_anonymoususersrole": true,
"mspp_createdon": "2026-01-21T22:10:56Z",
"mspp_modifiedon": "2026-01-21T22:10:56Z",
"statecode": 0,
"statuscode": 1,
"_mspp_websiteid_value": "5eb107a6-5ac2-4e1c-a3b9-d5c21bbc10ce",
"_mspp_createdby_value": "b7aa2026-a8c1-f011-bbd2-000d3a66196e",
"_mspp_modifiedby_value": "b7aa2026-a8c1-f011-bbd2-000d3a66196e"
}
]
```

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

```text
webroleid name statuscode
------------------------------------ --------------- ----------
a242a363-6077-4cb7-b2d1-1714502d129a Anonymous Users 1
```

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

```csv
mspp_modifiedon,mspp_key,mspp_description,mspp_authenticatedusersrole,statecode,_mspp_createdby_value,statuscode,mspp_anonymoususersrole,mspp_webroleid,mspp_createdon,_mspp_modifiedby_value,mspp_name,_mspp_websiteid_value
2026-01-21T22:10:56Z,,Role for anonymous users,0,0,b7aa2026-a8c1-f011-bbd2-000d3a66196e,1,1,a242a363-6077-4cb7-b2d1-1714502d129a,2026-01-21T22:10:56Z,b7aa2026-a8c1-f011-bbd2-000d3a66196e,Anonymous Users,5eb107a6-5ac2-4e1c-a3b9-d5c21bbc10ce
```

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

```md
# pp website webrole list --websiteName "Contoso" --environmentName "Default-2ca3eaa5-140f-4175-8261-3272edf9f339"

Date: 2/8/2026

Property | Value
---------|-------
mspp\_modifiedon | 2026-01-21T22:10:53Z
mspp\_description | Role for anonymous users
mspp\_authenticatedusersrole | true
statecode | 0
\_mspp\_createdby\_value | b7aa2026-a8c1-f011-bbd2-000d3a66196e
statuscode | 1
mspp\_anonymoususersrole | false
mspp\_webroleid | cc3bf86b-204c-4a97-b0b6-f788c62ae5e8
mspp\_createdon | 2026-01-21T22:10:53Z
\_mspp\_modifiedby\_value | b7aa2026-a8c1-f011-bbd2-000d3a66196e
mspp\_name | Authenticated Users
\_mspp\_websiteid\_value | 5eb107a6-5ac2-4e1c-a3b9-d5c21bbc10ce
```

</TabItem>
</Tabs>
5 changes: 5 additions & 0 deletions docs/src/config/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1996,6 +1996,11 @@ const sidebars: SidebarsConfig = {
type: 'doc',
label: 'website get',
id: 'cmd/pp/website/website-get'
},
{
type: 'doc',
label: 'website webrole list',
id: 'cmd/pp/website/website-webrole-list'
}
]
}
Expand Down
3 changes: 2 additions & 1 deletion src/m365/pp/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ export default {
SOLUTION_PUBLISHER_REMOVE: `${prefix} solution publisher remove`,
TENANT_SETTINGS_LIST: `${prefix} tenant settings list`,
TENANT_SETTINGS_SET: `${prefix} tenant settings set`,
WEBSITE_GET: `${prefix} website get`
WEBSITE_GET: `${prefix} website get`,
WEBSITE_WEBROLE_LIST: `${prefix} website webrole list`
};
15 changes: 15 additions & 0 deletions src/m365/pp/commands/website/Webrole.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export interface Webrole {
mspp_webroleid: string;
mspp_name: string;
mspp_description: string | null;
mspp_key: string | null;
mspp_authenticatedusersrole: boolean;
mspp_anonymoususersrole: boolean;
mspp_createdon: string;
mspp_modifiedon: string;
statecode: number;
statuscode: number;
_mspp_websiteid_value: string;
_mspp_createdby_value: string;
_mspp_modifiedby_value: string;
}
196 changes: 196 additions & 0 deletions src/m365/pp/commands/website/website-webrole-list.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import assert from 'assert';
import sinon from 'sinon';
import auth from '../../../../Auth.js';
import { cli } from '../../../../cli/cli.js';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { Logger } from '../../../../cli/Logger.js';
import { CommandError } from '../../../../Command.js';
import { telemetry } from '../../../../telemetry.js';
import { accessToken } from '../../../../utils/accessToken.js';
import { odata } from '../../../../utils/odata.js';
import { pid } from '../../../../utils/pid.js';
import { powerPlatform } from '../../../../utils/powerPlatform.js';
import { session } from '../../../../utils/session.js';
import { sinonUtil } from '../../../../utils/sinonUtil.js';
import commands from '../../commands.js';
import command, { options } from './website-webrole-list.js';

const environment = 'Default-727dc1e9-3cd1-4d1f-8102-ab5c936e52f0';
const powerPageResponse = {
"@odata.metadata": "https://api.powerplatform.com/powerpages/environments/Default-727dc1e9-3cd1-4d1f-8102-ab5c936e52f0/websites/$metadata#Websites",
"id": "4916bb2c-91e1-4716-91d5-b6171928fac9",
"name": "Site 1",
"createdOn": "2024-10-27T12:00:03",
"templateName": "DefaultPortalTemplate",
"websiteUrl": "https://site-0uaq9.powerappsportals.com",
"tenantId": "727dc1e9-3cd1-4d1f-8102-ab5c936e52f0",
"dataverseInstanceUrl": "https://org0cd4b2b9.crm4.dynamics.com/",
"environmentName": "Contoso (default)",
"environmentId": "Default-727dc1e9-3cd1-4d1f-8102-ab5c936e52f0",
"dataverseOrganizationId": "2d58aeac-74d4-4939-98d1-e05a70a655ba",
"selectedBaseLanguage": 1033,
"customHostNames": [],
"websiteRecordId": "5eb107a6-5ac2-4e1c-a3b9-d5c21bbc10ce",
"subdomain": "site-0uaq9",
"packageInstallStatus": "Installed",
"type": "Trial",
"trialExpiringInDays": 86,
"suspendedWebsiteDeletingInDays": 93,
"packageVersion": "9.6.9.39",
"isEarlyUpgradeEnabled": false,
"isCustomErrorEnabled": true,
"applicationUserAadAppId": "3f57aca7-5051-41b2-989d-26da8af7a53e",
"ownerId": "33469a62-c3af-4cfe-b893-854eceab96da",
"status": "OperationComplete",
"siteVisibility": "private",
"dataModel": "Enhanced"
};

const webroleResponse = [
{
"mspp_webroleid": "a242a363-6077-4cb7-b2d1-1714502d129a",
"mspp_name": "Anonymous Users",
"mspp_description": null,
"mspp_key": null,
"mspp_authenticatedusersrole": false,
"mspp_anonymoususersrole": true,
"mspp_createdon": "2026-01-21T22:10:56Z",
"mspp_modifiedon": "2026-01-21T22:10:56Z",
"statecode": 0,
"statuscode": 1,
"_mspp_websiteid_value": "5eb107a6-5ac2-4e1c-a3b9-d5c21bbc10ce",
"_mspp_createdby_value": "b7aa2026-a8c1-f011-bbd2-000d3a66196e",
"_mspp_modifiedby_value": "b7aa2026-a8c1-f011-bbd2-000d3a66196e"
}
];

describe(commands.WEBSITE_WEBROLE_LIST, () => {
let log: any[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let commandInfo: CommandInfo;
let commandOptionsSchema: typeof options;

before(() => {
sinon.stub(auth, 'restoreAuth').resolves();
sinon.stub(telemetry, 'trackEvent').resolves();
sinon.stub(pid, 'getProcessName').returns('');
sinon.stub(session, 'getId').returns('');
sinon.stub(accessToken, 'assertAccessTokenType').returns();
auth.connection.active = true;
commandInfo = cli.getCommandInfo(command);
commandOptionsSchema = commandInfo.command.getSchemaToParse() as typeof options;
});

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([
powerPlatform.getWebsiteById,
powerPlatform.getWebsiteIdByUniqueName,
powerPlatform.getDynamicsInstanceApiUrl,
odata.getAllItems
]);
});

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

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

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

it('fails validation if websiteName and websiteId are used at the same time', () => {
const actual = commandOptionsSchema.safeParse({
environmentName: environment,
websiteId: '4916bb2c-91e1-4716-91d5-b6171928fac9',
websiteName: 'Site 1'
});
assert.strictEqual(actual.success, false);
});

it('passes validation with only websiteId', () => {
const actual = commandOptionsSchema.safeParse({
environmentName: environment,
websiteId: '4916bb2c-91e1-4716-91d5-b6171928fac9'
});
assert.strictEqual(actual.success, true);
});

it('passes validation with only websiteName', () => {
const actual = commandOptionsSchema.safeParse({
environmentName: environment,
websiteName: 'Site 1'
});
assert.strictEqual(actual.success, true);
});

it('fails validation if neither websiteId, websiteName are provided', () => {
const actual = commandOptionsSchema.safeParse({
environmentName: environment
});
assert.strictEqual(actual.success, false);
});

it('retrieves webroles for Power Pages site by id', async () => {
sinon.stub(powerPlatform, 'getWebsiteById').resolves(powerPageResponse);
sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').resolves('https://org0cd4b2b9.crm4.dynamics.com');
sinon.stub(odata, 'getAllItems').resolves(webroleResponse);

await command.action(logger, { options: { verbose: true, environmentName: environment, websiteId: '4916bb2c-91e1-4716-91d5-b6171928fac9' } });
assert(loggerLogSpy.calledWith(webroleResponse));
});

it('retrieves webroles for Power Pages site by name', async () => {
sinon.stub(powerPlatform, 'getWebsiteIdByUniqueName').resolves('5eb107a6-5ac2-4e1c-a3b9-d5c21bbc10ce');
sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').resolves('https://org0cd4b2b9.crm4.dynamics.com');
sinon.stub(odata, 'getAllItems').resolves(webroleResponse);

await command.action(logger, { options: { verbose: true, environmentName: environment, websiteName: 'Site 1' } });
assert(loggerLogSpy.calledWith(webroleResponse));
});

it('outputs text friendly output when output is text', async () => {
sinon.stub(powerPlatform, 'getWebsiteById').resolves(powerPageResponse);
sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').resolves('https://org0cd4b2b9.crm4.dynamics.com');
sinon.stub(odata, 'getAllItems').resolves(webroleResponse);

await command.action(logger, { options: { environmentName: environment, websiteId: '4916bb2c-91e1-4716-91d5-b6171928fac9', output: 'text' } });
assert(loggerLogSpy.calledWith([
{
webroleid: 'a242a363-6077-4cb7-b2d1-1714502d129a',
name: 'Anonymous Users',
statuscode: 1
}
]));
});

it('correctly handles API OData error', async () => {
sinon.stub(powerPlatform, 'getWebsiteById').resolves(powerPageResponse);
sinon.stub(powerPlatform, 'getDynamicsInstanceApiUrl').resolves('https://org0cd4b2b9.crm4.dynamics.com');
sinon.stub(odata, 'getAllItems').rejects(new Error('An error has occurred'));

await assert.rejects(command.action(logger, { options: { environmentName: environment, websiteId: '4916bb2c-91e1-4716-91d5-b6171928fac9' } }),
new CommandError('An error has occurred'));
});
});
Loading