@pnp/cli-microsoft365 11.0.0-beta.4be9237 → 11.0.0-beta.677f8d3

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.
Files changed (43) hide show
  1. package/.devproxy/api-specs/sharepoint.yaml +54 -0
  2. package/.eslintrc.cjs +2 -0
  3. package/allCommands.json +1 -1
  4. package/allCommandsFull.json +1 -1
  5. package/dist/m365/entra/commands/app/app-add.js +14 -2
  6. package/dist/m365/entra/commands/roleassignment/roleassignment-add.js +146 -0
  7. package/dist/m365/entra/commands.js +1 -0
  8. package/dist/m365/flow/commands/environment/environment-get.js +19 -29
  9. package/dist/m365/outlook/commands/mail/mail-searchfolder-add.js +85 -0
  10. package/dist/m365/outlook/commands.js +1 -0
  11. package/dist/m365/pa/commands/environment/environment-get.js +18 -23
  12. package/dist/m365/pp/commands/copilot/copilot-get.js +0 -4
  13. package/dist/m365/pp/commands/copilot/copilot-list.js +0 -4
  14. package/dist/m365/pp/commands/copilot/copilot-remove.js +0 -4
  15. package/dist/m365/pp/commands/environment/environment-get.js +19 -26
  16. package/dist/m365/pp/commands.js +0 -3
  17. package/dist/m365/spfx/commands/project/project-upgrade.js +23 -66
  18. package/dist/m365/spo/commands/file/file-version-keep.js +78 -0
  19. package/dist/m365/spo/commands/homesite/homesite-get.js +28 -14
  20. package/dist/m365/spo/commands/homesite/homesite-list.js +1 -12
  21. package/dist/m365/spo/commands/homesite/homesite-remove.js +6 -34
  22. package/dist/m365/spo/commands/list/list-view-add.js +1 -1
  23. package/dist/m365/spo/commands/serviceprincipal/serviceprincipal-grant-list.js +17 -25
  24. package/dist/m365/spo/commands.js +1 -1
  25. package/dist/utils/entraAdministrativeUnit.js +1 -1
  26. package/dist/utils/entraApp.js +15 -0
  27. package/docs/docs/cmd/entra/app/app-add.mdx +7 -1
  28. package/docs/docs/cmd/entra/roleassignment/roleassignment-add.mdx +163 -0
  29. package/docs/docs/cmd/flow/environment/environment-get.mdx +6 -5
  30. package/docs/docs/cmd/outlook/mail/mail-searchfolder-add.mdx +147 -0
  31. package/docs/docs/cmd/pa/environment/environment-get.mdx +5 -2
  32. package/docs/docs/cmd/pp/copilot/copilot-get.mdx +0 -6
  33. package/docs/docs/cmd/pp/copilot/copilot-list.mdx +0 -6
  34. package/docs/docs/cmd/pp/copilot/copilot-remove.mdx +0 -6
  35. package/docs/docs/cmd/pp/environment/environment-get.mdx +5 -2
  36. package/docs/docs/cmd/spfx/project/project-upgrade.mdx +18 -5
  37. package/docs/docs/cmd/spo/file/file-version-keep.mdx +68 -0
  38. package/docs/docs/cmd/spo/homesite/homesite-get.mdx +44 -23
  39. package/docs/docs/cmd/spo/homesite/homesite-list.mdx +0 -6
  40. package/docs/docs/cmd/spo/homesite/homesite-remove.mdx +10 -35
  41. package/docs/docs/cmd/spo/list/list-view-add.mdx +11 -11
  42. package/docs/docs/cmd/spo/serviceprincipal/serviceprincipal-grant-list.mdx +18 -18
  43. package/package.json +1 -1
@@ -1,20 +1,25 @@
1
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
- };
6
- var _SpfxProjectUpgradeCommand_instances, _a, _SpfxProjectUpgradeCommand_initTelemetry, _SpfxProjectUpgradeCommand_initOptions, _SpfxProjectUpgradeCommand_initValidators;
7
1
  import fs from 'fs';
8
2
  import os from 'os';
9
3
  import path from 'path';
10
4
  // uncomment to support upgrading to preview releases
11
5
  import { prerelease } from 'semver';
12
- import { CommandError } from '../../../../Command.js';
6
+ import { z } from 'zod';
7
+ import { CommandError, globalOptionsZod } from '../../../../Command.js';
13
8
  import { fsUtil } from '../../../../utils/fsUtil.js';
14
9
  import { packageManager } from '../../../../utils/packageManager.js';
10
+ import { zod } from '../../../../utils/zod.js';
15
11
  import commands from '../../commands.js';
16
12
  import { BaseProjectCommand } from './base-project-command.js';
17
13
  import { FN017001_MISC_npm_dedupe } from './project-upgrade/rules/FN017001_MISC_npm_dedupe.js';
14
+ const options = globalOptionsZod
15
+ .extend({
16
+ packageManager: z.enum(['npm', 'pnpm', 'yarn']).default('npm'),
17
+ preview: z.boolean().optional(),
18
+ toVersion: zod.alias('v', z.string().optional()),
19
+ shell: z.enum(['bash', 'powershell', 'cmd']).default('powershell'),
20
+ output: z.enum(['json', 'text', 'md', 'tour', 'csv', 'none']).optional()
21
+ })
22
+ .strict();
18
23
  class SpfxProjectUpgradeCommand extends BaseProjectCommand {
19
24
  get name() {
20
25
  return commands.PROJECT_UPGRADE;
@@ -25,12 +30,14 @@ class SpfxProjectUpgradeCommand extends BaseProjectCommand {
25
30
  get allowedOutputs() {
26
31
  return ['json', 'text', 'md', 'tour'];
27
32
  }
33
+ get schema() {
34
+ return options;
35
+ }
28
36
  constructor() {
29
37
  super();
30
- _SpfxProjectUpgradeCommand_instances.add(this);
31
38
  this.toVersion = '';
32
- this.packageManager = 'npm';
33
- this.shell = 'bash';
39
+ this.packageManager = '';
40
+ this.shell = '';
34
41
  this.allFindings = [];
35
42
  this.supportedVersions = [
36
43
  '1.0.0',
@@ -80,14 +87,11 @@ class SpfxProjectUpgradeCommand extends BaseProjectCommand {
80
87
  '1.21.1',
81
88
  '1.22.0-beta.1'
82
89
  ];
83
- __classPrivateFieldGet(this, _SpfxProjectUpgradeCommand_instances, "m", _SpfxProjectUpgradeCommand_initTelemetry).call(this);
84
- __classPrivateFieldGet(this, _SpfxProjectUpgradeCommand_instances, "m", _SpfxProjectUpgradeCommand_initOptions).call(this);
85
- __classPrivateFieldGet(this, _SpfxProjectUpgradeCommand_instances, "m", _SpfxProjectUpgradeCommand_initValidators).call(this);
86
90
  }
87
91
  async commandAction(logger, args) {
88
92
  this.projectRootPath = this.getProjectRoot(process.cwd());
89
93
  if (this.projectRootPath === null) {
90
- throw new CommandError(`Couldn't find project root folder`, _a.ERROR_NO_PROJECT_ROOT_FOLDER);
94
+ throw new CommandError(`Couldn't find project root folder`, SpfxProjectUpgradeCommand.ERROR_NO_PROJECT_ROOT_FOLDER);
91
95
  }
92
96
  this.toVersion = args.options.toVersion ? args.options.toVersion : this.supportedVersions[this.supportedVersions.length - 1];
93
97
  // uncomment to support upgrading to preview releases
@@ -101,21 +105,21 @@ class SpfxProjectUpgradeCommand extends BaseProjectCommand {
101
105
  this.toVersion = this.supportedVersions[this.supportedVersions.length - 2];
102
106
  }
103
107
  this.packageManager = args.options.packageManager || 'npm';
104
- this.shell = args.options.shell || 'bash';
108
+ this.shell = args.options.shell || 'powershell';
105
109
  if (this.supportedVersions.indexOf(this.toVersion) < 0) {
106
- throw new CommandError(`CLI for Microsoft 365 doesn't support upgrading SharePoint Framework projects to version ${this.toVersion}. Supported versions are ${this.supportedVersions.join(', ')}`, _a.ERROR_UNSUPPORTED_TO_VERSION);
110
+ throw new CommandError(`CLI for Microsoft 365 doesn't support upgrading SharePoint Framework projects to version ${this.toVersion}. Supported versions are ${this.supportedVersions.join(', ')}`, SpfxProjectUpgradeCommand.ERROR_UNSUPPORTED_TO_VERSION);
107
111
  }
108
112
  this.projectVersion = this.getProjectVersion();
109
113
  if (!this.projectVersion) {
110
- throw new CommandError(`Unable to determine the version of the current SharePoint Framework project`, _a.ERROR_NO_VERSION);
114
+ throw new CommandError(`Unable to determine the version of the current SharePoint Framework project`, SpfxProjectUpgradeCommand.ERROR_NO_VERSION);
111
115
  }
112
116
  const pos = this.supportedVersions.indexOf(this.projectVersion);
113
117
  if (pos < 0) {
114
- throw new CommandError(`CLI for Microsoft 365 doesn't support upgrading projects built using SharePoint Framework v${this.projectVersion}`, _a.ERROR_UNSUPPORTED_FROM_VERSION);
118
+ throw new CommandError(`CLI for Microsoft 365 doesn't support upgrading projects built using SharePoint Framework v${this.projectVersion}`, SpfxProjectUpgradeCommand.ERROR_UNSUPPORTED_FROM_VERSION);
115
119
  }
116
120
  const posTo = this.supportedVersions.indexOf(this.toVersion);
117
121
  if (pos > posTo) {
118
- throw new CommandError('You cannot downgrade a project', _a.ERROR_NO_DOWNGRADE);
122
+ throw new CommandError('You cannot downgrade a project', SpfxProjectUpgradeCommand.ERROR_NO_DOWNGRADE);
119
123
  }
120
124
  if (pos === posTo) {
121
125
  await logger.log(`Project doesn't need to be upgraded`);
@@ -479,53 +483,6 @@ ${f.resolution}
479
483
  };
480
484
  }
481
485
  }
482
- _a = SpfxProjectUpgradeCommand, _SpfxProjectUpgradeCommand_instances = new WeakSet(), _SpfxProjectUpgradeCommand_initTelemetry = function _SpfxProjectUpgradeCommand_initTelemetry() {
483
- this.telemetry.push((args) => {
484
- Object.assign(this.telemetryProperties, {
485
- toVersion: args.options.toVersion || this.supportedVersions[this.supportedVersions.length - 1],
486
- packageManager: args.options.packageManager || 'npm',
487
- shell: args.options.shell || 'bash',
488
- preview: args.options.preview
489
- });
490
- // uncomment to support upgrading to preview releases
491
- if (prerelease(this.telemetryProperties.toVersion) && !args.options.preview) {
492
- this.telemetryProperties.toVersion = this.supportedVersions[this.supportedVersions.length - 2];
493
- }
494
- });
495
- }, _SpfxProjectUpgradeCommand_initOptions = function _SpfxProjectUpgradeCommand_initOptions() {
496
- this.options.unshift({
497
- option: '-v, --toVersion [toVersion]'
498
- }, {
499
- option: '--packageManager [packageManager]',
500
- autocomplete: _a.packageManagers
501
- }, {
502
- option: '--shell [shell]',
503
- autocomplete: _a.shells
504
- }, {
505
- option: '--preview'
506
- });
507
- this.options.forEach(o => {
508
- if (o.option.indexOf('--output') > -1) {
509
- o.autocomplete = this.allowedOutputs;
510
- }
511
- });
512
- }, _SpfxProjectUpgradeCommand_initValidators = function _SpfxProjectUpgradeCommand_initValidators() {
513
- this.validators.push(async (args) => {
514
- if (args.options.packageManager) {
515
- if (_a.packageManagers.indexOf(args.options.packageManager) < 0) {
516
- return `${args.options.packageManager} is not a supported package manager. Supported package managers are ${_a.packageManagers.join(', ')}`;
517
- }
518
- }
519
- if (args.options.shell) {
520
- if (_a.shells.indexOf(args.options.shell) < 0) {
521
- return `${args.options.shell} is not a supported shell. Supported shells are ${_a.shells.join(', ')}`;
522
- }
523
- }
524
- return true;
525
- });
526
- };
527
- SpfxProjectUpgradeCommand.packageManagers = ['npm', 'pnpm', 'yarn'];
528
- SpfxProjectUpgradeCommand.shells = ['bash', 'powershell', 'cmd'];
529
486
  SpfxProjectUpgradeCommand.ERROR_NO_PROJECT_ROOT_FOLDER = 1;
530
487
  SpfxProjectUpgradeCommand.ERROR_UNSUPPORTED_TO_VERSION = 2;
531
488
  SpfxProjectUpgradeCommand.ERROR_NO_VERSION = 3;
@@ -0,0 +1,78 @@
1
+ import commands from '../../commands.js';
2
+ import SpoCommand from '../../../base/SpoCommand.js';
3
+ import { globalOptionsZod } from '../../../../Command.js';
4
+ import { z } from 'zod';
5
+ import { zod } from '../../../../utils/zod.js';
6
+ import { validation } from '../../../../utils/validation.js';
7
+ import { urlUtil } from '../../../../utils/urlUtil.js';
8
+ import request from '../../../../request.js';
9
+ import { formatting } from '../../../../utils/formatting.js';
10
+ import { odata } from '../../../../utils/odata.js';
11
+ export const options = globalOptionsZod
12
+ .extend({
13
+ webUrl: zod.alias('u', z.string()
14
+ .refine(url => validation.isValidSharePointUrl(url) === true, url => ({
15
+ message: `'${url}' is not a valid SharePoint Online site URL.`
16
+ }))),
17
+ fileUrl: z.string().optional(),
18
+ fileId: zod.alias('i', z.string()
19
+ .refine(id => validation.isValidGuid(id), id => ({
20
+ message: `'${id}' is not a valid GUID.`
21
+ })).optional()),
22
+ label: z.string()
23
+ })
24
+ .strict();
25
+ class SpoFileVersionKeepCommand extends SpoCommand {
26
+ get name() {
27
+ return commands.FILE_VERSION_KEEP;
28
+ }
29
+ get description() {
30
+ return 'Ensure that a specific file version will never expire';
31
+ }
32
+ get schema() {
33
+ return options;
34
+ }
35
+ getRefinedSchema(schema) {
36
+ return schema
37
+ .refine(options => [options.fileUrl, options.fileId].filter(o => o !== undefined).length === 1, {
38
+ message: `Specify 'fileUrl' or 'fileId', but not both.`
39
+ });
40
+ }
41
+ async commandAction(logger, args) {
42
+ if (this.verbose) {
43
+ await logger.logToStderr(`Ensuring version '${args.options.label}' of file '${args.options.fileUrl || args.options.fileId}' at site '${args.options.webUrl}' will never expire...`);
44
+ }
45
+ try {
46
+ const baseApiUrl = this.getBaseApiUrl(args.options.webUrl, args.options.fileUrl, args.options.fileId);
47
+ const response = await odata.getAllItems(`${baseApiUrl}/versions?$filter=VersionLabel eq '${formatting.encodeQueryParameter(args.options.label)}'&$select=ID`);
48
+ if (response.length === 0) {
49
+ throw `Version with label '${args.options.label}' not found.`;
50
+ }
51
+ const requestExpirationOptions = {
52
+ url: `${baseApiUrl}/versions(${response[0].ID})/SetExpirationDate()`,
53
+ headers: {
54
+ accept: 'application/json;odata=nometadata',
55
+ 'content-type': 'application/json'
56
+ },
57
+ responseType: 'json'
58
+ };
59
+ await request.post(requestExpirationOptions);
60
+ }
61
+ catch (err) {
62
+ this.handleRejectedODataJsonPromise(err);
63
+ }
64
+ }
65
+ getBaseApiUrl(webUrl, fileUrl, fileId) {
66
+ let requestUrl;
67
+ if (fileUrl) {
68
+ const serverRelUrl = urlUtil.getServerRelativePath(webUrl, fileUrl);
69
+ requestUrl = `${webUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl='${formatting.encodeQueryParameter(serverRelUrl)}')`;
70
+ }
71
+ else {
72
+ requestUrl = `${webUrl}/_api/web/GetFileById('${fileId}')`;
73
+ }
74
+ return requestUrl;
75
+ }
76
+ }
77
+ export default new SpoFileVersionKeepCommand();
78
+ //# sourceMappingURL=file-version-keep.js.map
@@ -1,28 +1,42 @@
1
- import request from '../../../../request.js';
1
+ import { z } from 'zod';
2
+ import { zod } from '../../../../utils/zod.js';
3
+ import { globalOptionsZod } from '../../../../Command.js';
4
+ import { validation } from '../../../../utils/validation.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
+ import { odata } from '../../../../utils/odata.js';
9
+ import { urlUtil } from '../../../../utils/urlUtil.js';
10
+ const options = globalOptionsZod
11
+ .extend({
12
+ url: zod.alias('u', z.string()
13
+ .refine(url => validation.isValidSharePointUrl(url) === true, url => ({
14
+ message: `'${url}' is not a valid SharePoint Online site URL.`
15
+ })))
16
+ })
17
+ .strict();
5
18
  class SpoHomeSiteGetCommand extends SpoCommand {
6
19
  get name() {
7
20
  return commands.HOMESITE_GET;
8
21
  }
9
22
  get description() {
10
- return 'Gets information about the Home Site';
23
+ return 'Gets information about a home site';
11
24
  }
12
- async commandAction(logger) {
25
+ get schema() {
26
+ return options;
27
+ }
28
+ async commandAction(logger, args) {
13
29
  try {
14
- const spoUrl = await spo.getSpoUrl(logger, this.debug);
15
- const requestOptions = {
16
- url: `${spoUrl}/_api/SP.SPHSite/Details`,
17
- headers: {
18
- accept: 'application/json;odata=nometadata'
19
- },
20
- responseType: 'json'
21
- };
22
- const res = await request.get(requestOptions);
23
- if (!res["odata.null"]) {
24
- await logger.log(res);
30
+ const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.verbose);
31
+ if (this.verbose) {
32
+ await logger.log(`Retrieving home sites...`);
33
+ }
34
+ const homeSites = await odata.getAllItems(`${spoAdminUrl}/_api/SPO.Tenant/GetTargetedSitesDetails`);
35
+ const homeSite = homeSites.find(hs => urlUtil.removeTrailingSlashes(hs.Url).toLowerCase() === urlUtil.removeTrailingSlashes(args.options.url).toLowerCase());
36
+ if (homeSite === undefined) {
37
+ throw `Home site with URL '${args.options.url}' not found.`;
25
38
  }
39
+ await logger.log(homeSite);
26
40
  }
27
41
  catch (err) {
28
42
  this.handleRejectedODataJsonPromise(err);
@@ -9,27 +9,16 @@ class SpoHomeSiteListCommand extends SpoCommand {
9
9
  get description() {
10
10
  return 'Lists all home sites';
11
11
  }
12
- alias() {
13
- return [commands.TENANT_HOMESITE_LIST];
14
- }
15
12
  defaultProperties() {
16
13
  return ['Url', 'Title'];
17
14
  }
18
15
  async commandAction(logger) {
19
- await this.showDeprecationWarning(logger, commands.TENANT_HOMESITE_LIST, commands.HOMESITE_LIST);
20
16
  try {
21
17
  const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.verbose);
22
- const requestOptions = {
23
- url: `${spoAdminUrl}/_api/SPO.Tenant/GetTargetedSitesDetails`,
24
- headers: {
25
- accept: 'application/json;odata=nometadata'
26
- },
27
- responseType: 'json'
28
- };
29
18
  if (this.verbose) {
30
19
  await logger.logToStderr(`Retrieving all home sites...`);
31
20
  }
32
- const res = await odata.getAllItems(requestOptions);
21
+ const res = await odata.getAllItems(`${spoAdminUrl}/_api/SPO.Tenant/GetTargetedSitesDetails`);
33
22
  await logger.log(res);
34
23
  }
35
24
  catch (err) {
@@ -3,7 +3,6 @@ import { zod } from '../../../../utils/zod.js';
3
3
  import { globalOptionsZod } from '../../../../Command.js';
4
4
  import { validation } from '../../../../utils/validation.js';
5
5
  import { cli } from '../../../../cli/cli.js';
6
- import config from '../../../../config.js';
7
6
  import request from '../../../../request.js';
8
7
  import { spo } from '../../../../utils/spo.js';
9
8
  import SpoCommand from '../../../base/SpoCommand.js';
@@ -13,7 +12,7 @@ const options = globalOptionsZod
13
12
  url: zod.alias('u', z.string()
14
13
  .refine(url => validation.isValidSharePointUrl(url) === true, url => ({
15
14
  message: `'${url}' is not a valid SharePoint Online site URL.`
16
- })).optional()),
15
+ }))),
17
16
  force: zod.alias('f', z.boolean().optional())
18
17
  })
19
18
  .strict();
@@ -30,34 +29,8 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
30
29
  async commandAction(logger, args) {
31
30
  const removeHomeSite = async () => {
32
31
  try {
33
- if (this.verbose) {
34
- await logger.logToStderr(`Removing ${args.options.url ? `'${args.options.url}' as home site` : 'the current home site'}...`);
35
- }
36
32
  const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
37
- const reqDigest = await spo.getRequestDigest(spoAdminUrl);
38
- if (args.options.url) {
39
- await this.removeHomeSiteByUrl(args.options.url, spoAdminUrl, logger);
40
- await logger.log(`${args.options.url} has been removed as a Home Site. It may take some time for the change to apply. Check aka.ms/homesites for details.`);
41
- }
42
- else {
43
- await this.warn(logger, `The current way this command works is deprecated and will change in the next major release. The '--url' option will become required.`);
44
- const requestOptions = {
45
- url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
46
- headers: {
47
- 'X-RequestDigest': reqDigest.FormDigestValue
48
- },
49
- data: `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="28" ObjectPathId="27" /><Method Name="RemoveSPHSite" Id="29" ObjectPathId="27" /></Actions><ObjectPaths><Constructor Id="27" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
50
- };
51
- const res = await request.post(requestOptions);
52
- const json = JSON.parse(res);
53
- const response = json[0];
54
- if (response.ErrorInfo) {
55
- throw response.ErrorInfo.ErrorMessage;
56
- }
57
- else {
58
- await logger.log(json[json.length - 1]);
59
- }
60
- }
33
+ await this.removeHomeSiteByUrl(args.options.url, spoAdminUrl, logger);
61
34
  }
62
35
  catch (err) {
63
36
  this.handleRejectedODataJsonPromise(err);
@@ -67,11 +40,7 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
67
40
  await removeHomeSite();
68
41
  }
69
42
  else {
70
- const result = await cli.promptForConfirmation({
71
- message: args.options.url
72
- ? `Are you sure you want to remove '${args.options.url}' as home site?`
73
- : `Are you sure you want to remove the current home site?`
74
- });
43
+ const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove '${args.options.url}' as home site?` });
75
44
  if (result) {
76
45
  await removeHomeSite();
77
46
  }
@@ -79,6 +48,9 @@ class SpoHomeSiteRemoveCommand extends SpoCommand {
79
48
  }
80
49
  async removeHomeSiteByUrl(siteUrl, spoAdminUrl, logger) {
81
50
  const siteAdminProperties = await spo.getSiteAdminPropertiesByUrl(siteUrl, false, logger, this.verbose);
51
+ if (this.verbose) {
52
+ await logger.logToStderr(`Removing '${siteUrl}' as home site...`);
53
+ }
82
54
  const requestOptions = {
83
55
  url: `${spoAdminUrl}/_api/SPO.Tenant/RemoveTargetedSite`,
84
56
  headers: {
@@ -114,7 +114,7 @@ class SpoListViewAddCommand extends SpoCommand {
114
114
  Query: args.options.viewQuery,
115
115
  PersonalView: !!args.options.personal,
116
116
  SetAsDefaultView: !!args.options.default,
117
- Paged: !!args.options.paged,
117
+ Paged: args.options.paged ?? true,
118
118
  RowLimit: args.options.rowLimit ?? 30,
119
119
  CustomFormatter: args.options.customFormatter
120
120
  }
@@ -1,9 +1,11 @@
1
- import config from '../../../../config.js';
2
1
  import request from '../../../../request.js';
3
- import { spo } from '../../../../utils/spo.js';
4
- import SpoCommand from '../../../base/SpoCommand.js';
2
+ import GraphCommand from '../../../base/GraphCommand.js';
5
3
  import commands from '../../commands.js';
6
- class SpoServicePrincipalGrantListCommand extends SpoCommand {
4
+ class SpoServicePrincipalGrantListCommand extends GraphCommand {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.spoServicePrincipalDisplayName = 'SharePoint Online Web Client Extensibility';
8
+ }
7
9
  get name() {
8
10
  return commands.SERVICEPRINCIPAL_GRANT_LIST;
9
11
  }
@@ -15,36 +17,26 @@ class SpoServicePrincipalGrantListCommand extends SpoCommand {
15
17
  }
16
18
  async commandAction(logger) {
17
19
  try {
18
- const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
19
20
  if (this.verbose) {
20
- await logger.logToStderr(`Retrieving request digest...`);
21
+ await logger.logToStderr(`Retrieving permissions granted to the service principal '${this.spoServicePrincipalDisplayName}'...`);
21
22
  }
22
- const reqDigest = await spo.getRequestDigest(spoAdminUrl);
23
23
  const requestOptions = {
24
- url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
24
+ url: `${this.resource}/v1.0/servicePrincipals?$filter=displayName eq '${this.spoServicePrincipalDisplayName}'&$select=id`,
25
25
  headers: {
26
- 'X-RequestDigest': reqDigest.FormDigestValue
26
+ accept: 'application/json;odata.metadata=none'
27
27
  },
28
- data: `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009"><Actions><ObjectPath Id="4" ObjectPathId="3" /><ObjectPath Id="6" ObjectPathId="5" /><Query Id="7" ObjectPathId="5"><Query SelectAllProperties="true"><Properties /></Query><ChildItemQuery SelectAllProperties="true"><Properties /></ChildItemQuery></Query></Actions><ObjectPaths><Constructor Id="3" TypeId="{104e8f06-1e00-4675-99c6-1b9b504ed8d8}" /><Property Id="5" ParentId="3" Name="PermissionGrants" /></ObjectPaths></Request>`
28
+ responseType: 'json'
29
29
  };
30
- const res = await request.post(requestOptions);
31
- const json = JSON.parse(res);
32
- const response = json[0];
33
- if (response.ErrorInfo) {
34
- throw response.ErrorInfo.ErrorMessage;
35
- }
36
- else {
37
- const result = json[json.length - 1]._Child_Items_;
38
- await logger.log(result.map(r => {
39
- delete r._ObjectType_;
40
- delete r.ClientId;
41
- delete r.ConsentType;
42
- return r;
43
- }));
30
+ const response = await request.get(requestOptions);
31
+ if (response.value.length === 0) {
32
+ throw `Service principal '${this.spoServicePrincipalDisplayName}' not found`;
44
33
  }
34
+ requestOptions.url = `${this.resource}/v1.0/servicePrincipals/${response.value[0].id}/oauth2PermissionGrants`;
35
+ const result = await request.get(requestOptions);
36
+ await logger.log(result.value);
45
37
  }
46
38
  catch (err) {
47
- this.handleRejectedPromise(err);
39
+ this.handleRejectedODataJsonPromise(err);
48
40
  }
49
41
  }
50
42
  }
@@ -83,6 +83,7 @@ export default {
83
83
  FILE_SHARINGLINK_SET: `${prefix} file sharinglink set`,
84
84
  FILE_VERSION_CLEAR: `${prefix} file version clear`,
85
85
  FILE_VERSION_GET: `${prefix} file version get`,
86
+ FILE_VERSION_KEEP: `${prefix} file version keep`,
86
87
  FILE_VERSION_LIST: `${prefix} file version list`,
87
88
  FILE_VERSION_REMOVE: `${prefix} file version remove`,
88
89
  FILE_VERSION_RESTORE: `${prefix} file version restore`,
@@ -324,7 +325,6 @@ export default {
324
325
  TENANT_COMMANDSET_LIST: `${prefix} tenant commandset list`,
325
326
  TENANT_COMMANDSET_REMOVE: `${prefix} tenant commandset remove`,
326
327
  TENANT_COMMANDSET_SET: `${prefix} tenant commandset set`,
327
- TENANT_HOMESITE_LIST: `${prefix} tenant homesite list`,
328
328
  TENANT_RECYCLEBINITEM_LIST: `${prefix} tenant recyclebinitem list`,
329
329
  TENANT_RECYCLEBINITEM_REMOVE: `${prefix} tenant recyclebinitem remove`,
330
330
  TENANT_RECYCLEBINITEM_RESTORE: `${prefix} tenant recyclebinitem restore`,
@@ -19,7 +19,7 @@ export const entraAdministrativeUnit = {
19
19
  }
20
20
  }
21
21
  const queryString = queryParameters.length > 0
22
- ? `?${queryParameters.join('&')}`
22
+ ? `&${queryParameters.join('&')}`
23
23
  : '';
24
24
  const graphResource = 'https://graph.microsoft.com';
25
25
  const administrativeUnits = await odata.getAllItems(`${graphResource}/v1.0/directory/administrativeUnits?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'${queryString}`);
@@ -143,6 +143,21 @@ export const entraApp = {
143
143
  redirectUris: options.redirectUris.split(',').map(u => u.trim())
144
144
  };
145
145
  }
146
+ if (options.platform === 'android') {
147
+ applicationInfo['publicClient'] = {
148
+ redirectUris: [
149
+ `msauth://${options.bundleId}/${formatting.encodeQueryParameter(options.signatureHash)}`
150
+ ]
151
+ };
152
+ }
153
+ if (options.platform === 'apple') {
154
+ applicationInfo['publicClient'] = {
155
+ redirectUris: [
156
+ `msauth://code/msauth.${options.bundleId}%3A%2F%2Fauth`,
157
+ `msauth.${options.bundleId}://auth`
158
+ ]
159
+ };
160
+ }
146
161
  if (options.implicitFlow) {
147
162
  if (!applicationInfo.web) {
148
163
  applicationInfo.web = {};
@@ -31,7 +31,7 @@ m365 entra appregistration add [options]
31
31
  : Comma-separated list of redirect URIs. Requires `platform` to be specified.
32
32
 
33
33
  `-p, --platform [platform]`
34
- : Platform for which the `redirectUris` should be configured. Allowed values `spa`, `web`, `publicClient`. Requires `redirectUris` to be specified.
34
+ : Platform for which the app should be configured. Allowed values `spa`, `web`, `publicClient`, `apple`, `android`.
35
35
 
36
36
  `--implicitFlow`
37
37
  : Specify, to indicate that the authorization endpoint should return ID and access tokens.
@@ -75,6 +75,12 @@ m365 entra appregistration add [options]
75
75
  `--manifest [manifest]`
76
76
  : App manifest as retrieved from Entra ID to create the app registration from. Specify either `name` or `manifest` but not both.
77
77
 
78
+ `--bundleId [bundleId]`
79
+ : Specify a bundle Id to add the iOS / macOS or Android platform to the application. Required when platform is `apple` or `android`.
80
+
81
+ `--signatureHash [signatureHash]`
82
+ : A required hash when specifying a bundle Id and platform `android`.
83
+
78
84
  `--save`
79
85
  : Use to store the information about the created app in a local file.
80
86