@pnp/cli-microsoft365 10.10.0 → 10.11.0-beta.5e075e5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/allCommands.json +1 -1
- package/allCommandsFull.json +1 -1
- package/dist/m365/cli/commands/app/app-add.js +95 -0
- package/dist/m365/cli/commands.js +1 -0
- package/dist/m365/spo/commands/page/Page.js +10 -3
- package/dist/m365/spo/commands/page/page-section-list.js +5 -1
- package/dist/m365/spo/commands/serviceprincipal/serviceprincipal-permissionrequest-list.js +13 -7
- package/dist/m365/spo/commands/site/site-appcatalog-list.js +38 -2
- package/docs/docs/cmd/cli/app/app-add.mdx +50 -0
- package/docs/docs/cmd/spo/site/site-appcatalog-list.mdx +11 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { globalOptionsZod } from '../../../../Command.js';
|
|
3
|
+
import { zod } from '../../../../utils/zod.js';
|
|
4
|
+
import config from '../../../../config.js';
|
|
5
|
+
import GraphCommand from '../../../base/GraphCommand.js';
|
|
6
|
+
import commands from '../../commands.js';
|
|
7
|
+
import { cli } from '../../../../cli/cli.js';
|
|
8
|
+
import { entraApp } from '../../../../utils/entraApp.js';
|
|
9
|
+
import { accessToken } from '../../../../utils/accessToken.js';
|
|
10
|
+
import auth from '../../../../Auth.js';
|
|
11
|
+
const options = globalOptionsZod
|
|
12
|
+
.extend({
|
|
13
|
+
name: zod.alias('n', z.string().optional().default('CLI for M365')),
|
|
14
|
+
scopes: zod.alias('s', z.string().optional().default('minimal')),
|
|
15
|
+
saveToConfig: z.boolean().optional()
|
|
16
|
+
})
|
|
17
|
+
.strict();
|
|
18
|
+
class CliAppAddCommand extends GraphCommand {
|
|
19
|
+
get name() {
|
|
20
|
+
return commands.APP_ADD;
|
|
21
|
+
}
|
|
22
|
+
get description() {
|
|
23
|
+
return 'Creates a Microsoft Entra application registration for CLI for Microsoft 365';
|
|
24
|
+
}
|
|
25
|
+
get schema() {
|
|
26
|
+
return options;
|
|
27
|
+
}
|
|
28
|
+
getRefinedSchema(schema) {
|
|
29
|
+
return schema
|
|
30
|
+
.refine(options => {
|
|
31
|
+
const scopes = options.scopes;
|
|
32
|
+
if (!scopes.includes(',')) {
|
|
33
|
+
return scopes === 'minimal' || scopes === 'all';
|
|
34
|
+
}
|
|
35
|
+
const scopeList = scopes.split(',').map(s => s.trim());
|
|
36
|
+
return scopeList.every(scope => scope.startsWith('https'));
|
|
37
|
+
}, {
|
|
38
|
+
message: "Scopes must be 'minimal', 'all', or comma-separated list of URLs starting with 'https'. 'minimal' and 'all' cannot be combined with other scopes.",
|
|
39
|
+
path: ['scopes']
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async commandAction(logger, args) {
|
|
43
|
+
try {
|
|
44
|
+
const options = {
|
|
45
|
+
allowPublicClientFlows: true,
|
|
46
|
+
apisDelegated: this.getScopes(args.options),
|
|
47
|
+
implicitFlow: false,
|
|
48
|
+
multitenant: false,
|
|
49
|
+
name: args.options.name,
|
|
50
|
+
platform: 'publicClient',
|
|
51
|
+
redirectUris: 'http://localhost,https://localhost,https://login.microsoftonline.com/common/oauth2/nativeclient'
|
|
52
|
+
};
|
|
53
|
+
const apis = await entraApp.resolveApis({
|
|
54
|
+
options,
|
|
55
|
+
logger,
|
|
56
|
+
verbose: this.verbose,
|
|
57
|
+
debug: this.debug
|
|
58
|
+
});
|
|
59
|
+
const appInfo = await entraApp.createAppRegistration({
|
|
60
|
+
options,
|
|
61
|
+
unknownOptions: {},
|
|
62
|
+
apis,
|
|
63
|
+
logger,
|
|
64
|
+
verbose: this.verbose,
|
|
65
|
+
debug: this.debug
|
|
66
|
+
});
|
|
67
|
+
appInfo.tenantId = accessToken.getTenantIdFromAccessToken(auth.connection.accessTokens[auth.defaultResource].accessToken);
|
|
68
|
+
await entraApp.grantAdminConsent({
|
|
69
|
+
appInfo,
|
|
70
|
+
appPermissions: entraApp.appPermissions,
|
|
71
|
+
adminConsent: true,
|
|
72
|
+
logger,
|
|
73
|
+
debug: this.debug
|
|
74
|
+
});
|
|
75
|
+
if (args.options.saveToConfig) {
|
|
76
|
+
cli.getConfig().set('clientId', appInfo.appId);
|
|
77
|
+
cli.getConfig().set('tenantId', appInfo.tenantId);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
this.handleRejectedODataJsonPromise(err);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
getScopes(options) {
|
|
85
|
+
if (options.scopes === 'all') {
|
|
86
|
+
return config.allScopes.join(',');
|
|
87
|
+
}
|
|
88
|
+
else if (options.scopes === 'minimal') {
|
|
89
|
+
return config.minimalScopes.join(',');
|
|
90
|
+
}
|
|
91
|
+
return options.scopes;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export default new CliAppAddCommand();
|
|
95
|
+
//# sourceMappingURL=app-add.js.map
|
|
@@ -72,10 +72,14 @@ export class Page {
|
|
|
72
72
|
return output;
|
|
73
73
|
}
|
|
74
74
|
static getSectionInformation(section, isJSONOutput) {
|
|
75
|
-
|
|
76
|
-
order: section.order
|
|
77
|
-
columns: section.columns.map(column => this.getColumnsInformation(column, isJSONOutput))
|
|
75
|
+
const sectionOutput = {
|
|
76
|
+
order: section.order
|
|
78
77
|
};
|
|
78
|
+
if (this.isVerticalSection(section)) {
|
|
79
|
+
sectionOutput.isVertical = true;
|
|
80
|
+
}
|
|
81
|
+
sectionOutput.columns = section.columns.map(column => this.getColumnsInformation(column, isJSONOutput));
|
|
82
|
+
return sectionOutput;
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
81
85
|
* Publish a modern page in SharePoint Online
|
|
@@ -99,5 +103,8 @@ export class Page {
|
|
|
99
103
|
}
|
|
100
104
|
return pageName;
|
|
101
105
|
}
|
|
106
|
+
static isVerticalSection(section) {
|
|
107
|
+
return section.layoutIndex === 2 && section?.controlData?.position?.sectionFactor === 12;
|
|
108
|
+
}
|
|
102
109
|
}
|
|
103
110
|
//# sourceMappingURL=Page.js.map
|
|
@@ -34,10 +34,14 @@ class SpoPageSectionListCommand extends SpoCommand {
|
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
36
|
await logger.log(output.map(s => {
|
|
37
|
-
|
|
37
|
+
const sectionOutput = {
|
|
38
38
|
order: s.order,
|
|
39
39
|
columns: s.columns.length
|
|
40
40
|
};
|
|
41
|
+
if (s.isVertical) {
|
|
42
|
+
sectionOutput.isVertical = s.isVertical;
|
|
43
|
+
}
|
|
44
|
+
return sectionOutput;
|
|
41
45
|
}));
|
|
42
46
|
}
|
|
43
47
|
}
|
|
@@ -45,9 +45,6 @@ class SpoServicePrincipalPermissionRequestListCommand extends SpoCommand {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
-
if (spoWebAppServicePrincipalPermissionRequestResult.length === 0) {
|
|
49
|
-
spoWebAppServicePrincipalPermissionRequestResult = result;
|
|
50
|
-
}
|
|
51
48
|
await logger.log(spoWebAppServicePrincipalPermissionRequestResult.map(r => {
|
|
52
49
|
return {
|
|
53
50
|
Id: r.Id.replace('/Guid(', '').replace(')/', ''),
|
|
@@ -71,14 +68,23 @@ class SpoServicePrincipalPermissionRequestListCommand extends SpoCommand {
|
|
|
71
68
|
responseType: 'json'
|
|
72
69
|
};
|
|
73
70
|
const response = await request.get(requestOptions);
|
|
74
|
-
if (response.value
|
|
75
|
-
return
|
|
71
|
+
if (!response.value || response.value.length === 0) {
|
|
72
|
+
return null;
|
|
76
73
|
}
|
|
77
|
-
|
|
74
|
+
const scopes = [];
|
|
75
|
+
response.value.forEach(grant => {
|
|
76
|
+
if (grant.scope) {
|
|
77
|
+
grant.scope.split(' ')
|
|
78
|
+
.map(permission => permission.trim())
|
|
79
|
+
.filter(Boolean)
|
|
80
|
+
.forEach(permission => scopes.push(permission));
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
return scopes;
|
|
78
84
|
}
|
|
79
85
|
async getSPOClientExtensibilityWebApplicationPrincipalId() {
|
|
80
86
|
const requestOptions = {
|
|
81
|
-
url: `https://graph.microsoft.com/v1.0/servicePrincipals/?$filter=displayName eq 'SharePoint Online Client Extensibility
|
|
87
|
+
url: `https://graph.microsoft.com/v1.0/servicePrincipals/?$filter=displayName eq 'SharePoint Online Web Client Extensibility'`,
|
|
82
88
|
headers: {
|
|
83
89
|
accept: 'application/json;odata.metadata=none'
|
|
84
90
|
},
|
|
@@ -1,7 +1,15 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { globalOptionsZod } from '../../../../Command.js';
|
|
3
|
+
import { zod } from '../../../../utils/zod.js';
|
|
1
4
|
import { odata } from '../../../../utils/odata.js';
|
|
2
5
|
import { spo } from '../../../../utils/spo.js';
|
|
3
6
|
import SpoCommand from '../../../base/SpoCommand.js';
|
|
4
7
|
import commands from '../../commands.js';
|
|
8
|
+
const options = globalOptionsZod
|
|
9
|
+
.extend({
|
|
10
|
+
excludeDeletedSites: zod.alias('excludeDeletedSites', z.boolean().optional())
|
|
11
|
+
})
|
|
12
|
+
.strict();
|
|
5
13
|
class SpoSiteAppCatalogListCommand extends SpoCommand {
|
|
6
14
|
get name() {
|
|
7
15
|
return commands.SITE_APPCATALOG_LIST;
|
|
@@ -9,16 +17,44 @@ class SpoSiteAppCatalogListCommand extends SpoCommand {
|
|
|
9
17
|
get description() {
|
|
10
18
|
return 'List all site collection app catalogs within the tenant';
|
|
11
19
|
}
|
|
20
|
+
get schema() {
|
|
21
|
+
return options;
|
|
22
|
+
}
|
|
12
23
|
defaultProperties() {
|
|
13
24
|
return ['AbsoluteUrl', 'SiteID'];
|
|
14
25
|
}
|
|
15
|
-
async commandAction(logger) {
|
|
26
|
+
async commandAction(logger, args) {
|
|
16
27
|
try {
|
|
17
28
|
if (this.verbose) {
|
|
18
29
|
await logger.logToStderr('Retrieving site collection app catalogs...');
|
|
19
30
|
}
|
|
20
31
|
const spoUrl = await spo.getSpoUrl(logger, this.debug);
|
|
21
|
-
|
|
32
|
+
let appCatalogs = await odata.getAllItems(`${spoUrl}/_api/Web/TenantAppCatalog/SiteCollectionAppCatalogsSites`);
|
|
33
|
+
if (args.options.excludeDeletedSites) {
|
|
34
|
+
if (this.verbose) {
|
|
35
|
+
await logger.logToStderr('Excluding inaccessible sites from the results...');
|
|
36
|
+
}
|
|
37
|
+
const activeAppCatalogs = [];
|
|
38
|
+
for (const appCatalog of appCatalogs) {
|
|
39
|
+
try {
|
|
40
|
+
await spo.getWeb(appCatalog.AbsoluteUrl, logger, this.verbose);
|
|
41
|
+
activeAppCatalogs.push(appCatalog);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
if (this.debug) {
|
|
45
|
+
await logger.logToStderr(error);
|
|
46
|
+
}
|
|
47
|
+
if (error.status === 404 || error.status === 403) {
|
|
48
|
+
if (this.verbose) {
|
|
49
|
+
await logger.logToStderr(`Site at '${appCatalog.AbsoluteUrl}' is inaccessible. Excluding from results...`);
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
appCatalogs = activeAppCatalogs;
|
|
57
|
+
}
|
|
22
58
|
await logger.log(appCatalogs);
|
|
23
59
|
}
|
|
24
60
|
catch (err) {
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import Global from '/docs/cmd/_global.mdx';
|
|
2
|
+
|
|
3
|
+
# cli app add
|
|
4
|
+
|
|
5
|
+
Create a new app registration to use for the CLI for Microsoft 365
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
m365 cli app add [options]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Options
|
|
14
|
+
|
|
15
|
+
```md definition-list
|
|
16
|
+
`-n, --name [name]`
|
|
17
|
+
: Name of the app registration. Defaults to CLI for M365
|
|
18
|
+
|
|
19
|
+
`-s, --scopes [scopes]`
|
|
20
|
+
: Which scopes should be added? Valid values are: `minimal`, `all`, or a list of scopes. Defaults to `minimal`.
|
|
21
|
+
|
|
22
|
+
`--saveToConfig`
|
|
23
|
+
: Save the app registration info to the CLI config. This way the new app registration will be used as the default app registration to sign in.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
<Global />
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
29
|
+
|
|
30
|
+
Create a new app registration to use for CLI for Microsoft 365
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
m365 cli app add
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Create a new app registration with all permission scopes and a custom name
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
m365 cli app add --name "Contoso CLI app" --scopes all
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Create a new app registration with self-defined scopes
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
m365 cli app add --scopes "https://graph.microsoft.com/User.Read,https://graph.microsoft.com/Group.Read.All"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Response
|
|
49
|
+
|
|
50
|
+
The command won't return a response on success
|
|
@@ -14,6 +14,11 @@ m365 spo site appcatalog list [options]
|
|
|
14
14
|
|
|
15
15
|
## Options
|
|
16
16
|
|
|
17
|
+
```md definition-list
|
|
18
|
+
`--excludeDeletedSites [excludeDeletedSites]`
|
|
19
|
+
: Exclude site collections that are no longer active
|
|
20
|
+
```
|
|
21
|
+
|
|
17
22
|
<Global />
|
|
18
23
|
|
|
19
24
|
## Remarks
|
|
@@ -32,6 +37,12 @@ List all site collection app catalogs within the tenant
|
|
|
32
37
|
m365 spo site appcatalog list
|
|
33
38
|
```
|
|
34
39
|
|
|
40
|
+
List all site collection app catalogs within the tenant and exclude deleted sites.
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
m365 spo site appcatalog list --excludeDeletedSites
|
|
44
|
+
```
|
|
45
|
+
|
|
35
46
|
## Response
|
|
36
47
|
|
|
37
48
|
<Tabs>
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnp/cli-microsoft365",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.11.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@pnp/cli-microsoft365",
|
|
9
|
-
"version": "10.
|
|
9
|
+
"version": "10.11.0",
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@azure/msal-common": "^15.8.0",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnp/cli-microsoft365",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.11.0-beta.5e075e5",
|
|
4
4
|
"description": "Manage Microsoft 365 and SharePoint Framework projects on any platform",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "./dist/api.js",
|
|
@@ -315,4 +315,4 @@
|
|
|
315
315
|
"sinon": "^21.0.0",
|
|
316
316
|
"source-map-support": "^0.5.21"
|
|
317
317
|
}
|
|
318
|
-
}
|
|
318
|
+
}
|