@pnp/cli-microsoft365 10.1.0-beta.10765f6 → 10.1.0-beta.63210ca

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 (101) hide show
  1. package/README.md +2 -2
  2. package/allCommands.json +1 -1
  3. package/allCommandsFull.json +1 -1
  4. package/dist/AuthServer.js +1 -1
  5. package/dist/Command.js +2 -2
  6. package/dist/cli/cli.js +2 -2
  7. package/dist/m365/base/AppCommand.js +5 -2
  8. package/dist/m365/entra/commands/administrativeunit/administrativeunit-get.js +18 -4
  9. package/dist/m365/entra/commands/administrativeunit/administrativeunit-list.js +34 -2
  10. package/dist/m365/entra/commands/app/app-get.js +17 -5
  11. package/dist/m365/entra/commands/app/app-list.js +34 -2
  12. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-add.js +3 -0
  13. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-get.js +3 -0
  14. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-list.js +3 -0
  15. package/dist/m365/entra/commands/group/group-get.js +6 -3
  16. package/dist/m365/entra/commands/group/group-list.js +16 -1
  17. package/dist/m365/entra/commands/m365group/m365group-add.js +1 -1
  18. package/dist/m365/entra/commands/m365group/m365group-conversation-list.js +21 -6
  19. package/dist/m365/entra/commands/m365group/m365group-get.js +29 -7
  20. package/dist/m365/entra/commands/m365group/m365group-list.js +1 -1
  21. package/dist/m365/entra/commands/m365group/m365group-remove.js +21 -9
  22. package/dist/m365/entra/commands/m365group/m365group-renew.js +19 -7
  23. package/dist/m365/entra/commands/m365group/m365group-set.js +1 -1
  24. package/dist/m365/entra/commands/m365group/m365group-teamify.js +12 -21
  25. package/dist/m365/file/commands/convert/convert-pdf.js +3 -4
  26. package/dist/m365/file/commands/file-add.js +5 -6
  27. package/dist/m365/graph/commands/subscription/subscription-add.js +46 -5
  28. package/dist/m365/pp/commands/{chatbot/chatbot-get.js → copilot/copilot-get.js} +24 -20
  29. package/dist/m365/pp/commands/{chatbot/chatbot-list.js → copilot/copilot-list.js} +16 -12
  30. package/dist/m365/pp/commands/{chatbot/chatbot-remove.js → copilot/copilot-remove.js} +28 -24
  31. package/dist/m365/pp/commands.js +3 -0
  32. package/dist/m365/spfx/commands/package/package-generate.js +1 -1
  33. package/dist/m365/spfx/commands/project/JsonRule.js +2 -2
  34. package/dist/m365/spfx/commands/project/project-upgrade/rules/FN016004_TS_property_pane_property_import.js +2 -2
  35. package/dist/m365/spfx/commands/spfx-doctor.js +1 -1
  36. package/dist/m365/spo/commands/contenttype/contenttype-get.js +2 -2
  37. package/dist/m365/spo/commands/contenttype/contenttype-list.js +6 -3
  38. package/dist/m365/spo/commands/file/file-add.js +1 -1
  39. package/dist/m365/spo/commands/file/file-retentionlabel-ensure.js +1 -2
  40. package/dist/m365/spo/commands/file/file-retentionlabel-remove.js +1 -2
  41. package/dist/m365/spo/commands/folder/folder-retentionlabel-ensure.js +1 -2
  42. package/dist/m365/spo/commands/folder/folder-retentionlabel-remove.js +1 -2
  43. package/dist/m365/spo/commands/list/list-contenttype-list.js +5 -2
  44. package/dist/m365/spo/commands/listitem/listitem-batch-remove.js +10 -8
  45. package/dist/m365/spo/commands/listitem/listitem-batch-set.js +1 -1
  46. package/dist/m365/spo/commands/listitem/listitem-retentionlabel-ensure.js +1 -2
  47. package/dist/m365/spo/commands/listitem/listitem-retentionlabel-remove.js +1 -2
  48. package/dist/m365/spo/commands/page/page-add.js +1 -1
  49. package/dist/m365/spo/commands/site/site-admin-add.js +4 -12
  50. package/dist/m365/spo/commands/site/site-admin-list.js +3 -11
  51. package/dist/m365/spo/commands/site/site-admin-remove.js +4 -12
  52. package/dist/m365/spo/commands/site/site-set.js +1 -1
  53. package/dist/m365/spp/commands/model/model-remove.js +105 -0
  54. package/dist/m365/spp/commands.js +2 -1
  55. package/dist/m365/teams/commands/user/user-app-list.js +1 -1
  56. package/dist/m365/tenant/commands/report/report-office365activationcounts.js +2 -8
  57. package/dist/m365/tenant/commands/report/report-office365activationsusercounts.js +2 -8
  58. package/dist/m365/tenant/commands/report/report-office365activationsuserdetail.js +2 -8
  59. package/dist/m365/todo/commands/list/list-remove.js +2 -1
  60. package/dist/m365/todo/commands/list/list-set.js +2 -1
  61. package/dist/m365/todo/commands/task/task-add.js +2 -1
  62. package/dist/m365/todo/commands/task/task-get.js +2 -1
  63. package/dist/m365/todo/commands/task/task-list.js +2 -1
  64. package/dist/m365/todo/commands/task/task-remove.js +2 -1
  65. package/dist/m365/todo/commands/task/task-set.js +1 -1
  66. package/dist/m365/viva/commands/engage/engage-community-set.js +111 -0
  67. package/dist/m365/viva/commands.js +1 -0
  68. package/dist/utils/entraAdministrativeUnit.js +14 -2
  69. package/dist/utils/entraGroup.js +49 -6
  70. package/dist/utils/formatting.js +8 -20
  71. package/dist/utils/spo.js +5 -4
  72. package/dist/utils/spp.js +3 -3
  73. package/dist/utils/urlUtil.js +11 -14
  74. package/docs/docs/cmd/entra/administrativeunit/administrativeunit-get.mdx +10 -3
  75. package/docs/docs/cmd/entra/administrativeunit/administrativeunit-list.mdx +16 -1
  76. package/docs/docs/cmd/entra/app/app-get.mdx +13 -8
  77. package/docs/docs/cmd/entra/app/app-list.mdx +16 -1
  78. package/docs/docs/cmd/entra/group/group-get.mdx +10 -3
  79. package/docs/docs/cmd/entra/group/group-list.mdx +9 -2
  80. package/docs/docs/cmd/entra/m365group/m365group-conversation-list.mdx +12 -3
  81. package/docs/docs/cmd/entra/m365group/m365group-get.mdx +29 -5
  82. package/docs/docs/cmd/entra/m365group/m365group-remove.mdx +7 -4
  83. package/docs/docs/cmd/entra/m365group/m365group-renew.mdx +11 -2
  84. package/docs/docs/cmd/entra/m365group/m365group-teamify.mdx +12 -3
  85. package/docs/docs/cmd/entra/m365group/m365group-user-add.mdx +2 -2
  86. package/docs/docs/cmd/entra/m365group/m365group-user-list.mdx +6 -0
  87. package/docs/docs/cmd/entra/m365group/m365group-user-remove.mdx +1 -1
  88. package/docs/docs/cmd/entra/m365group/m365group-user-set.mdx +3 -3
  89. package/docs/docs/cmd/graph/subscription/subscription-add.mdx +30 -5
  90. package/docs/docs/cmd/login.mdx +45 -44
  91. package/docs/docs/cmd/pp/{chatbot/chatbot-get.mdx → copilot/copilot-get.mdx} +24 -18
  92. package/docs/docs/cmd/pp/{chatbot/chatbot-list.mdx → copilot/copilot-list.mdx} +20 -14
  93. package/docs/docs/cmd/pp/{chatbot/chatbot-remove.mdx → copilot/copilot-remove.mdx} +16 -10
  94. package/docs/docs/cmd/pp/managementapp/managementapp-add.mdx +1 -1
  95. package/docs/docs/cmd/spo/contenttype/contenttype-get.mdx +7 -1
  96. package/docs/docs/cmd/spo/contenttype/contenttype-list.mdx +7 -1
  97. package/docs/docs/cmd/spo/list/list-contenttype-list.mdx +7 -1
  98. package/docs/docs/cmd/spp/model/model-remove.mdx +57 -0
  99. package/docs/docs/cmd/viva/engage/engage-community-set.mdx +61 -0
  100. package/npm-shrinkwrap.json +6 -0
  101. package/package.json +4 -2
@@ -5,6 +5,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
5
5
  };
6
6
  var _TodoListSetCommand_instances, _TodoListSetCommand_initTelemetry, _TodoListSetCommand_initOptions, _TodoListSetCommand_initOptionSets;
7
7
  import request from '../../../../request.js';
8
+ import { formatting } from '../../../../utils/formatting.js';
8
9
  import DelegatedGraphCommand from '../../../base/DelegatedGraphCommand.js';
9
10
  import commands from '../../commands.js';
10
11
  class TodoListSetCommand extends DelegatedGraphCommand {
@@ -52,7 +53,7 @@ class TodoListSetCommand extends DelegatedGraphCommand {
52
53
  return args.options.id;
53
54
  }
54
55
  const requestOptions = {
55
- url: `${endpoint}/me/todo/lists?$filter=displayName eq '${escape(args.options.name)}'`,
56
+ url: `${endpoint}/me/todo/lists?$filter=displayName eq '${formatting.encodeQueryParameter(args.options.name)}'`,
56
57
  headers: {
57
58
  accept: "application/json;odata.metadata=none"
58
59
  },
@@ -5,6 +5,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
5
5
  };
6
6
  var _TodoTaskAddCommand_instances, _a, _TodoTaskAddCommand_initTelemetry, _TodoTaskAddCommand_initOptions, _TodoTaskAddCommand_initValidators, _TodoTaskAddCommand_initOptionSets;
7
7
  import request from '../../../../request.js';
8
+ import { formatting } from '../../../../utils/formatting.js';
8
9
  import { validation } from '../../../../utils/validation.js';
9
10
  import DelegatedGraphCommand from '../../../base/DelegatedGraphCommand.js';
10
11
  import commands from '../../commands.js';
@@ -71,7 +72,7 @@ class TodoTaskAddCommand extends DelegatedGraphCommand {
71
72
  return args.options.listId;
72
73
  }
73
74
  const requestOptions = {
74
- url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${escape(args.options.listName)}'`,
75
+ url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${formatting.encodeQueryParameter(args.options.listName)}'`,
75
76
  headers: {
76
77
  accept: 'application/json;odata.metadata=none'
77
78
  },
@@ -6,6 +6,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
6
6
  var _TodoTaskGetCommand_instances, _TodoTaskGetCommand_initTelemetry, _TodoTaskGetCommand_initOptions, _TodoTaskGetCommand_initOptionSets;
7
7
  import { cli } from '../../../../cli/cli.js';
8
8
  import request from '../../../../request.js';
9
+ import { formatting } from '../../../../utils/formatting.js';
9
10
  import DelegatedGraphCommand from '../../../base/DelegatedGraphCommand.js';
10
11
  import commands from '../../commands.js';
11
12
  class TodoTaskGetCommand extends DelegatedGraphCommand {
@@ -30,7 +31,7 @@ class TodoTaskGetCommand extends DelegatedGraphCommand {
30
31
  return args.options.listId;
31
32
  }
32
33
  const requestOptions = {
33
- url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${escape(args.options.listName)}'`,
34
+ url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${formatting.encodeQueryParameter(args.options.listName)}'`,
34
35
  headers: {
35
36
  accept: 'application/json;odata.metadata=none'
36
37
  },
@@ -6,6 +6,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
6
6
  var _TodoTaskListCommand_instances, _TodoTaskListCommand_initTelemetry, _TodoTaskListCommand_initOptions, _TodoTaskListCommand_initOptionSets;
7
7
  import { cli } from '../../../../cli/cli.js';
8
8
  import request from '../../../../request.js';
9
+ import { formatting } from '../../../../utils/formatting.js';
9
10
  import { odata } from '../../../../utils/odata.js';
10
11
  import DelegatedGraphCommand from '../../../base/DelegatedGraphCommand.js';
11
12
  import commands from '../../commands.js';
@@ -31,7 +32,7 @@ class TodoTaskListCommand extends DelegatedGraphCommand {
31
32
  return args.options.listId;
32
33
  }
33
34
  const requestOptions = {
34
- url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${escape(args.options.listName)}'`,
35
+ url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${formatting.encodeQueryParameter(args.options.listName)}'`,
35
36
  headers: {
36
37
  accept: 'application/json;odata.metadata=none'
37
38
  },
@@ -6,6 +6,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
6
6
  var _TodoTaskRemoveCommand_instances, _TodoTaskRemoveCommand_initTelemetry, _TodoTaskRemoveCommand_initOptions, _TodoTaskRemoveCommand_initOptionSets;
7
7
  import { cli } from '../../../../cli/cli.js';
8
8
  import request from '../../../../request.js';
9
+ import { formatting } from '../../../../utils/formatting.js';
9
10
  import DelegatedGraphCommand from '../../../base/DelegatedGraphCommand.js';
10
11
  import commands from '../../commands.js';
11
12
  class TodoTaskRemoveCommand extends DelegatedGraphCommand {
@@ -37,7 +38,7 @@ class TodoTaskRemoveCommand extends DelegatedGraphCommand {
37
38
  if (options.listName) {
38
39
  // Search list by its name
39
40
  const requestOptions = {
40
- url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${escape(options.listName)}'`,
41
+ url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${formatting.encodeQueryParameter(options.listName)}'`,
41
42
  headers: {
42
43
  accept: "application/json;odata.metadata=none"
43
44
  },
@@ -50,7 +50,7 @@ class TodoTaskSetCommand extends DelegatedGraphCommand {
50
50
  return options.listId;
51
51
  }
52
52
  const requestOptions = {
53
- url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${escape(options.listName)}'`,
53
+ url: `${this.resource}/v1.0/me/todo/lists?$filter=displayName eq '${formatting.encodeQueryParameter(options.listName)}'`,
54
54
  headers: {
55
55
  accept: 'application/json;odata.metadata=none'
56
56
  },
@@ -0,0 +1,111 @@
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 _VivaEngageCommunitySetCommand_instances, _VivaEngageCommunitySetCommand_initTelemetry, _VivaEngageCommunitySetCommand_initOptions, _VivaEngageCommunitySetCommand_initValidators, _VivaEngageCommunitySetCommand_initTypes, _VivaEngageCommunitySetCommand_initOptionSets;
7
+ import request from '../../../../request.js';
8
+ import { validation } from '../../../../utils/validation.js';
9
+ import { vivaEngage } from '../../../../utils/vivaEngage.js';
10
+ import GraphCommand from '../../../base/GraphCommand.js';
11
+ import commands from '../../commands.js';
12
+ class VivaEngageCommunitySetCommand extends GraphCommand {
13
+ get name() {
14
+ return commands.ENGAGE_COMMUNITY_SET;
15
+ }
16
+ get description() {
17
+ return 'Updates an existing Viva Engage community';
18
+ }
19
+ constructor() {
20
+ super();
21
+ _VivaEngageCommunitySetCommand_instances.add(this);
22
+ this.privacyOptions = ['public', 'private'];
23
+ __classPrivateFieldGet(this, _VivaEngageCommunitySetCommand_instances, "m", _VivaEngageCommunitySetCommand_initTelemetry).call(this);
24
+ __classPrivateFieldGet(this, _VivaEngageCommunitySetCommand_instances, "m", _VivaEngageCommunitySetCommand_initOptions).call(this);
25
+ __classPrivateFieldGet(this, _VivaEngageCommunitySetCommand_instances, "m", _VivaEngageCommunitySetCommand_initValidators).call(this);
26
+ __classPrivateFieldGet(this, _VivaEngageCommunitySetCommand_instances, "m", _VivaEngageCommunitySetCommand_initTypes).call(this);
27
+ __classPrivateFieldGet(this, _VivaEngageCommunitySetCommand_instances, "m", _VivaEngageCommunitySetCommand_initOptionSets).call(this);
28
+ }
29
+ async commandAction(logger, args) {
30
+ let communityId = args.options.id;
31
+ if (args.options.displayName) {
32
+ communityId = (await vivaEngage.getCommunityByDisplayName(args.options.displayName, ['id'])).id;
33
+ }
34
+ else if (args.options.entraGroupId) {
35
+ communityId = (await vivaEngage.getCommunityByEntraGroupId(args.options.entraGroupId, ['id'])).id;
36
+ }
37
+ if (this.verbose) {
38
+ await logger.logToStderr(`Updating Viva Engage community with ID ${communityId}...`);
39
+ }
40
+ const requestOptions = {
41
+ url: `${this.resource}/v1.0/employeeExperience/communities/${communityId}`,
42
+ headers: {
43
+ accept: 'application/json;odata.metadata=none'
44
+ },
45
+ responseType: 'json',
46
+ data: {
47
+ description: args.options.description,
48
+ displayName: args.options.newDisplayName,
49
+ privacy: args.options.privacy
50
+ }
51
+ };
52
+ try {
53
+ await request.patch(requestOptions);
54
+ }
55
+ catch (err) {
56
+ this.handleRejectedODataJsonPromise(err);
57
+ }
58
+ }
59
+ }
60
+ _VivaEngageCommunitySetCommand_instances = new WeakSet(), _VivaEngageCommunitySetCommand_initTelemetry = function _VivaEngageCommunitySetCommand_initTelemetry() {
61
+ this.telemetry.push((args) => {
62
+ Object.assign(this.telemetryProperties, {
63
+ id: typeof args.options.id !== 'undefined',
64
+ displayName: typeof args.options.displayName !== 'undefined',
65
+ entraGroupId: typeof args.options.entraGroupId !== 'undefined',
66
+ newDisplayName: typeof args.options.newDisplayName !== 'undefined',
67
+ description: typeof args.options.description !== 'undefined',
68
+ privacy: typeof args.options.privacy !== 'undefined'
69
+ });
70
+ });
71
+ }, _VivaEngageCommunitySetCommand_initOptions = function _VivaEngageCommunitySetCommand_initOptions() {
72
+ this.options.unshift({
73
+ option: '-i, --id [id]'
74
+ }, {
75
+ option: '-d, --displayName [displayName]'
76
+ }, {
77
+ option: '--entraGroupId [entraGroupId]'
78
+ }, {
79
+ option: '--newDisplayName [newDisplayName]'
80
+ }, {
81
+ option: '--description [description]'
82
+ }, {
83
+ option: '--privacy [privacy]',
84
+ autocomplete: this.privacyOptions
85
+ });
86
+ }, _VivaEngageCommunitySetCommand_initValidators = function _VivaEngageCommunitySetCommand_initValidators() {
87
+ this.validators.push(async (args) => {
88
+ if (args.options.entraGroupId && !validation.isValidGuid(args.options.entraGroupId)) {
89
+ return `${args.options.entraGroupId} is not a valid GUID for the option 'entraGroupId'.`;
90
+ }
91
+ if (args.options.newDisplayName && args.options.newDisplayName.length > 255) {
92
+ return `The maximum amount of characters for 'newDisplayName' is 255.`;
93
+ }
94
+ if (args.options.description && args.options.description.length > 1024) {
95
+ return `The maximum amount of characters for 'description' is 1024.`;
96
+ }
97
+ if (args.options.privacy && this.privacyOptions.map(x => x.toLowerCase()).indexOf(args.options.privacy.toLowerCase()) === -1) {
98
+ return `${args.options.privacy} is not a valid privacy. Allowed values are ${this.privacyOptions.join(', ')}`;
99
+ }
100
+ if (!args.options.newDisplayName && !args.options.description && !args.options.privacy) {
101
+ return 'Specify at least newDisplayName, description, or privacy.';
102
+ }
103
+ return true;
104
+ });
105
+ }, _VivaEngageCommunitySetCommand_initTypes = function _VivaEngageCommunitySetCommand_initTypes() {
106
+ this.types.string.push('id', 'displayName', 'entraGroupId', 'newDisplayName', 'description', 'privacy');
107
+ }, _VivaEngageCommunitySetCommand_initOptionSets = function _VivaEngageCommunitySetCommand_initOptionSets() {
108
+ this.optionSets.push({ options: ['id', 'displayName', 'entraGroupId'] });
109
+ };
110
+ export default new VivaEngageCommunitySetCommand();
111
+ //# sourceMappingURL=engage-community-set.js.map
@@ -4,6 +4,7 @@ export default {
4
4
  ENGAGE_COMMUNITY_ADD: `${prefix} engage community add`,
5
5
  ENGAGE_COMMUNITY_GET: `${prefix} engage community get`,
6
6
  ENGAGE_COMMUNITY_LIST: `${prefix} engage community list`,
7
+ ENGAGE_COMMUNITY_SET: `${prefix} engage community set`,
7
8
  ENGAGE_COMMUNITY_USER_LIST: `${prefix} engage community user list`,
8
9
  ENGAGE_GROUP_LIST: `${prefix} engage group list`,
9
10
  ENGAGE_GROUP_USER_ADD: `${prefix} engage group user add`,
@@ -5,12 +5,24 @@ export const entraAdministrativeUnit = {
5
5
  /**
6
6
  * Get an administrative unit by its display name.
7
7
  * @param displayName Administrative unit display name.
8
+ * @param properties Properties to include in the response.
8
9
  * @returns The administrative unit.
9
10
  * @throws Error when administrative unit was not found.
10
11
  */
11
- async getAdministrativeUnitByDisplayName(displayName) {
12
+ async getAdministrativeUnitByDisplayName(displayName, properties) {
13
+ const queryParameters = [];
14
+ if (properties) {
15
+ const allProperties = properties.split(',');
16
+ const selectProperties = allProperties.filter(prop => !prop.includes('/'));
17
+ if (selectProperties.length > 0) {
18
+ queryParameters.push(`$select=${selectProperties}`);
19
+ }
20
+ }
21
+ const queryString = queryParameters.length > 0
22
+ ? `?${queryParameters.join('&')}`
23
+ : '';
12
24
  const graphResource = 'https://graph.microsoft.com';
13
- const administrativeUnits = await odata.getAllItems(`${graphResource}/v1.0/directory/administrativeUnits?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`);
25
+ const administrativeUnits = await odata.getAllItems(`${graphResource}/v1.0/directory/administrativeUnits?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'${queryString}`);
14
26
  if (administrativeUnits.length === 0) {
15
27
  throw `The specified administrative unit '${displayName}' does not exist.`;
16
28
  }
@@ -7,10 +7,22 @@ export const entraGroup = {
7
7
  /**
8
8
  * Retrieve a single group.
9
9
  * @param id Group ID.
10
+ * @param properties Properties to include in the response.
10
11
  */
11
- async getGroupById(id) {
12
+ async getGroupById(id, properties) {
13
+ const queryParameters = [];
14
+ if (properties) {
15
+ const allProperties = properties.split(',');
16
+ const selectProperties = allProperties.filter(prop => !prop.includes('/'));
17
+ if (selectProperties.length > 0) {
18
+ queryParameters.push(`$select=${selectProperties}`);
19
+ }
20
+ }
21
+ const queryString = queryParameters.length > 0
22
+ ? `?${queryParameters.join('&')}`
23
+ : '';
12
24
  const requestOptions = {
13
- url: `${graphResource}/v1.0/groups/${id}`,
25
+ url: `${graphResource}/v1.0/groups/${id}${queryString}`,
14
26
  headers: {
15
27
  accept: 'application/json;odata.metadata=none'
16
28
  },
@@ -21,18 +33,31 @@ export const entraGroup = {
21
33
  /**
22
34
  * Get a list of groups by display name.
23
35
  * @param displayName Group display name.
36
+ * @param properties Properties to include in the response.
24
37
  */
25
- async getGroupsByDisplayName(displayName) {
26
- return odata.getAllItems(`${graphResource}/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'`);
38
+ async getGroupsByDisplayName(displayName, properties) {
39
+ const queryParameters = [];
40
+ if (properties) {
41
+ const allProperties = properties.split(',');
42
+ const selectProperties = allProperties.filter(prop => !prop.includes('/'));
43
+ if (selectProperties.length > 0) {
44
+ queryParameters.push(`$select=${selectProperties}`);
45
+ }
46
+ }
47
+ const queryString = queryParameters.length > 0
48
+ ? `&${queryParameters.join('&')}`
49
+ : '';
50
+ return odata.getAllItems(`${graphResource}/v1.0/groups?$filter=displayName eq '${formatting.encodeQueryParameter(displayName)}'${queryString}`);
27
51
  },
28
52
  /**
29
53
  * Get a single group by its display name.
30
54
  * @param displayName Group display name.
55
+ * @param properties Properties to include in the response.
31
56
  * @throws Error when group was not found.
32
57
  * @throws Error when multiple groups with the same name were found.
33
58
  */
34
- async getGroupByDisplayName(displayName) {
35
- const groups = await this.getGroupsByDisplayName(displayName);
59
+ async getGroupByDisplayName(displayName, properties) {
60
+ const groups = await this.getGroupsByDisplayName(displayName, properties);
36
61
  if (!groups.length) {
37
62
  throw Error(`The specified group '${displayName}' does not exist.`);
38
63
  }
@@ -60,6 +85,24 @@ export const entraGroup = {
60
85
  }
61
86
  return groups[0].id;
62
87
  },
88
+ /**
89
+ * Get id of a group by its mail nickname.
90
+ * @param mailNickname Group mail nickname.
91
+ * @throws Error when group was not found.
92
+ * @throws Error when multiple groups with the same name were found.
93
+ */
94
+ async getGroupIdByMailNickname(mailNickname) {
95
+ const groups = await odata.getAllItems(`${graphResource}/v1.0/groups?$filter=mailNickname eq '${formatting.encodeQueryParameter(mailNickname)}'&$select=id`);
96
+ if (!groups.length) {
97
+ throw Error(`The specified group '${mailNickname}' does not exist.`);
98
+ }
99
+ if (groups.length > 1) {
100
+ const resultAsKeyValuePair = formatting.convertArrayToHashTable('id', groups);
101
+ const result = await cli.handleMultipleResultsFound(`Multiple groups with mail nickname '${mailNickname}' found.`, resultAsKeyValuePair);
102
+ return result.id;
103
+ }
104
+ return groups[0].id;
105
+ },
63
106
  async setGroup(id, isPrivate, logger, verbose) {
64
107
  if (verbose && logger) {
65
108
  await logger.logToStderr(`Updating Microsoft 365 Group ${id}...`);
@@ -1,3 +1,4 @@
1
+ import { parse } from 'csv-parse/sync';
1
2
  import chalk from 'chalk';
2
3
  import stripJsonComments from 'strip-json-comments';
3
4
  import { BasePermissions } from '../m365/spo/base-permissions.js';
@@ -75,26 +76,13 @@ export const formatting = {
75
76
  return response;
76
77
  },
77
78
  parseCsvToJson(s, quoteChar = '"', delimiter = ',') {
78
- const regex = new RegExp(`\\s*(${quoteChar})?(.*?)\\1\\s*(?:${delimiter}|$)`, 'gs');
79
- const lines = s.split('\n');
80
- const match = (line) => [...line.matchAll(regex)]
81
- .map(m => m[2]); // we only want the second capture group
82
- const heads = match(lines[0]).slice(0, -1);
83
- return lines.slice(1)
84
- .filter(text => text.trim() !== '')
85
- .map(line => {
86
- const lineMatch = match(line);
87
- const obj = {};
88
- heads.forEach((key, index) => {
89
- const value = parseInt(lineMatch[index]);
90
- if (isNaN(value) || value.toString() !== lineMatch[index]) {
91
- obj[key] = lineMatch[index];
92
- }
93
- else {
94
- obj[key] = parseInt(lineMatch[index]);
95
- }
96
- });
97
- return obj;
79
+ return parse(s, {
80
+ quote: quoteChar,
81
+ delimiter: delimiter,
82
+ columns: true,
83
+ skipEmptyLines: true,
84
+ ltrim: true,
85
+ cast: true
98
86
  });
99
87
  },
100
88
  encodeQueryParameter(value) {
package/dist/utils/spo.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import os from 'os';
2
- import url from 'url';
3
2
  import { urlUtil } from "./urlUtil.js";
4
3
  import { validation } from "./validation.js";
5
4
  import auth from '../Auth.js';
@@ -200,8 +199,10 @@ export const spo = {
200
199
  * @param siteAccessToken a valid access token for the site specified in the webFullUrl param
201
200
  */
202
201
  async ensureFolder(webFullUrl, folderToEnsure, logger, debug) {
203
- const webUrl = url.parse(webFullUrl);
204
- if (!webUrl.protocol || !webUrl.hostname) {
202
+ try {
203
+ new URL(webFullUrl);
204
+ }
205
+ catch {
205
206
  throw new Error('webFullUrl is not a valid URL');
206
207
  }
207
208
  if (!folderToEnsure) {
@@ -1060,7 +1061,7 @@ export const spo = {
1060
1061
  headers: {
1061
1062
  'X-RequestDigest': context.FormDigestValue
1062
1063
  },
1063
- 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>${payload.join('')}<ObjectPath Id="14" ObjectPathId="13" /><ObjectIdentityQuery Id="15" ObjectPathId="5" /><Query Id="16" ObjectPathId="13"><Query SelectAllProperties="false"><Properties><Property Name="IsComplete" ScalarProperty="true" /><Property Name="PollingInterval" ScalarProperty="true" /></Properties></Query></Query></Actions><ObjectPaths><Identity Id="5" Name="53d8499e-d0d2-5000-cb83-9ade5be42ca4|${tenantId.substr(pos, tenantId.indexOf('&') - pos)}&#xA;SiteProperties&#xA;${formatting.encodeQueryParameter(url)}" /><Method Id="13" ParentId="5" Name="Update" /></ObjectPaths></Request>`
1064
+ 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>${payload.join('')}<ObjectPath Id="14" ObjectPathId="13" /><ObjectIdentityQuery Id="15" ObjectPathId="5" /><Query Id="16" ObjectPathId="13"><Query SelectAllProperties="false"><Properties><Property Name="IsComplete" ScalarProperty="true" /><Property Name="PollingInterval" ScalarProperty="true" /></Properties></Query></Query></Actions><ObjectPaths><Identity Id="5" Name="53d8499e-d0d2-5000-cb83-9ade5be42ca4|${tenantId.substring(pos, tenantId.indexOf('&'))}&#xA;SiteProperties&#xA;${formatting.encodeQueryParameter(url)}" /><Method Id="13" ParentId="5" Name="Update" /></ObjectPaths></Request>`
1064
1065
  };
1065
1066
  const res = await request.post(requestOptionsUpdateProperties);
1066
1067
  const json = JSON.parse(res);
package/dist/utils/spp.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import request from '../request.js';
2
2
  export const spp = {
3
3
  /**
4
- * Asserts whether the specified site is a content center.
5
- * @param siteUrl The URL of the site to check.
6
- * @throws Error when the site is not a content center.
4
+ * Asserts whether the specified site is a content center
5
+ * @param siteUrl The URL of the site to check
6
+ * @throws error when site is not a content center.
7
7
  */
8
8
  async assertSiteIsContentCenter(siteUrl) {
9
9
  const requestOptions = {
@@ -1,4 +1,3 @@
1
- import url from 'url';
2
1
  export const urlUtil = {
3
2
  /**
4
3
  * Returns server relative path.
@@ -15,12 +14,7 @@ export const urlUtil = {
15
14
  * urlUtil.getServerRelativePath("/sites/team1/", "/Shared Documents");
16
15
  */
17
16
  getServerRelativePath(webUrl, folderRelativePath) {
18
- const tenantUrl = `${url.parse(webUrl).protocol}//${url.parse(webUrl).hostname}`;
19
- // if webUrl is a server-relative URL then tenantUrl will resolve to null//null
20
- // in which case we should keep webUrl
21
- let webRelativePath = tenantUrl !== 'null//null' ? webUrl.substr(tenantUrl.length) : webUrl;
22
- // will be used to remove relative path from the folderRelativePath
23
- // in case the web relative url is included
17
+ let webRelativePath = this.getUrlRelativePath(webUrl);
24
18
  let relativePathToRemove = webRelativePath;
25
19
  // add '/' at 0
26
20
  if (webRelativePath[0] !== '/') {
@@ -90,11 +84,8 @@ export const urlUtil = {
90
84
  * Utils.getWebRelativePath("/sites/team1/", "/sites/team1/Shared Documents");
91
85
  */
92
86
  getWebRelativePath(webUrl, folderUrl) {
87
+ let webRelativePath = this.getUrlRelativePath(webUrl);
93
88
  let folderWebRelativePath = '';
94
- const tenantUrl = `${url.parse(webUrl).protocol}//${url.parse(webUrl).hostname}`;
95
- // if webUrl is a server-relative URL then tenantUrl will resolve to null//null
96
- // in which case we should keep webUrl
97
- let webRelativePath = tenantUrl !== 'null//null' ? webUrl.substr(tenantUrl.length) : webUrl;
98
89
  // will be used to remove relative path from the folderRelativePath
99
90
  // in case the web relative url is included
100
91
  let relativePathToRemove = webRelativePath;
@@ -140,12 +131,11 @@ export const urlUtil = {
140
131
  * urlUtil.getAbsoluteUrl("https://contoso.sharepoint.com/sites/team1/", "/sites/team1/Lists/MyList");
141
132
  */
142
133
  getAbsoluteUrl(webUrl, serverRelativeUrl) {
143
- const uri = url.parse(webUrl);
144
- const tenantUrl = `${uri.protocol}//${uri.hostname}`;
134
+ const parsedUrl = new URL(webUrl);
145
135
  if (serverRelativeUrl[0] !== '/') {
146
136
  serverRelativeUrl = `/${serverRelativeUrl}`;
147
137
  }
148
- return `${tenantUrl}${serverRelativeUrl}`;
138
+ return `${parsedUrl.origin}${serverRelativeUrl}`;
149
139
  },
150
140
  /**
151
141
  * Combines base and relative url considering any missing slashes
@@ -213,6 +203,13 @@ export const urlUtil = {
213
203
  */
214
204
  removeTrailingSlashes(url) {
215
205
  return url.replace(/\/+$/, '');
206
+ },
207
+ getUrlRelativePath(url) {
208
+ if (url.includes('://')) {
209
+ const parsedUrl = new URL(url);
210
+ return url.substring(parsedUrl.origin.length);
211
+ }
212
+ return url;
216
213
  }
217
214
  };
218
215
  //# sourceMappingURL=urlUtil.js.map
@@ -20,22 +20,29 @@ m365 entra administrativeunit get [options]
20
20
 
21
21
  `-n, --displayName [displayName]`
22
22
  : The display name of the administrative unit. Specify either `id` or `displayName` but not both.
23
+
24
+ `-p, --properties [properties]`
25
+ : Comma-separated list of properties to retrieve.
23
26
  ```
24
27
 
25
28
  <Global />
26
29
 
30
+ ## Remarks
31
+
32
+ Using the `--properties` option, you can specify a comma-separated list of administrative unit properties to retrieve from the Microsoft Graph. If you don't specify any properties, the command will output the default properties returned by Graph.
33
+
27
34
  ## Examples
28
35
 
29
- Get information about the administrative unit by its id
36
+ Get information about the administrative unit by its id.
30
37
 
31
38
  ```sh
32
39
  m365 entra administrativeunit get --id 03c4c9dc-6f0c-4c4f-a4e6-0c9ed80f54c7
33
40
  ```
34
41
 
35
- Get information about the administrative unit by its display name
42
+ Get information about the administrative unit by its display name with specified properties.
36
43
 
37
44
  ```sh
38
- m365 entra administrativeunit get --displayName 'Marketing Division'
45
+ m365 entra administrativeunit get --displayName "Marketing Division" --properties "id,displayName"
39
46
  ```
40
47
 
41
48
  ## Response
@@ -14,16 +14,31 @@ m365 entra administrativeunit list [options]
14
14
 
15
15
  ## Options
16
16
 
17
+ ```md definition-list
18
+ `-p, --properties [properties]`
19
+ : Comma-separated list of properties to retrieve.
20
+ ```
21
+
17
22
  <Global />
18
23
 
24
+ ## Remarks
25
+
26
+ Using the `--properties` option, you can specify a comma-separated list of administrative unit properties to retrieve from the Microsoft Graph. If you don't specify any properties, the command will output the default properties returned by Graph.
27
+
19
28
  ## Examples
20
29
 
21
- Retrieve a list of administrative units
30
+ Retrieve a list of administrative units.
22
31
 
23
32
  ```sh
24
33
  m365 entra administrativeunit list
25
34
  ```
26
35
 
36
+ Retrieve a list of administrative units with specified properties.
37
+
38
+ ```sh
39
+ m365 entra administrativeunit list --properties "id,displayName"
40
+ ```
41
+
27
42
  ## Response
28
43
 
29
44
  <Tabs>
@@ -22,16 +22,19 @@ m365 entra appregistration get [options]
22
22
 
23
23
  ```md definition-list
24
24
  `--appId [appId]`
25
- : Application (client) ID of the Entra application registration to get. Specify either `appId`, `objectId` or `name`
25
+ : Application (client) ID of the Entra application registration to get. Specify either `appId`, `objectId` or `name`.
26
26
 
27
27
  `--objectId [objectId]`
28
- : Object ID of the Entra application registration to get. Specify either `appId`, `objectId` or `name`
28
+ : Object ID of the Entra application registration to get. Specify either `appId`, `objectId` or `name`.
29
29
 
30
30
  `--name [name]`
31
- : Name of the Entra application registration to get. Specify either `appId`, `objectId` or `name`
31
+ : Name of the Entra application registration to get. Specify either `appId`, `objectId` or `name`.
32
32
 
33
33
  `--save`
34
- : Use to store the information about the created app in a local file
34
+ : Use to store the information about the created app in a local file.
35
+
36
+ `-p, --properties [properties]`
37
+ : Comma-separated list of properties to retrieve.
35
38
  ```
36
39
 
37
40
  <Global />
@@ -44,24 +47,26 @@ If the command finds multiple Entra application registrations with the specified
44
47
 
45
48
  If you want to store the information about the Entra app registration, use the `--save` option. This is useful when you build solutions connected to Microsoft 365 and want to easily manage app registrations used with your solution. When you use the `--save` option, after you get the app registration, the command will write its ID and name to the `.m365rc.json` file in the current directory. If the file already exists, it will add the information about the App registration to it if it's not already present, allowing you to track multiple apps. If the file doesn't exist, the command will create it.
46
49
 
50
+ Using the `--properties` option, you can specify a comma-separated list of app properties to retrieve from the Microsoft Graph. If you don't specify any properties, the command will output the default properties returned by Graph.
51
+
47
52
  ## Examples
48
53
 
49
- Get the Entra application registration by its app (client) ID
54
+ Get the Entra application registration by its app (client) ID.
50
55
 
51
56
  ```sh
52
57
  m365 entra app get --appId d75be2e1-0204-4f95-857d-51a37cf40be8
53
58
  ```
54
59
 
55
- Get the Entra application registration by its object ID
60
+ Get the Entra application registration by its object ID.
56
61
 
57
62
  ```sh
58
63
  m365 entra app get --objectId d75be2e1-0204-4f95-857d-51a37cf40be8
59
64
  ```
60
65
 
61
- Get the Entra application registration by its name
66
+ Get the Entra application registration by its name with specified properties.
62
67
 
63
68
  ```sh
64
- m365 entra app get --name "My app"
69
+ m365 entra app get --name "My app" --properties "appId,displayName"
65
70
  ```
66
71
 
67
72
  Get the Entra application registration by its name. Store information about the retrieved app registration in the _.m365rc.json_ file in the current directory.
@@ -20,16 +20,31 @@ m365 entra appregistration list [options]
20
20
 
21
21
  ## Options
22
22
 
23
+ ```md definition-list
24
+ `-p, --properties [properties]`
25
+ : Comma-separated list of properties to retrieve.
26
+ ```
27
+
23
28
  <Global />
24
29
 
30
+ ## Remarks
31
+
32
+ Using the `--properties` option, you can specify a comma-separated list of app properties to retrieve from the Microsoft Graph. If you don't specify any properties, the command will output the default properties returned by Graph.
33
+
25
34
  ## Examples
26
35
 
27
- Retrieve a list of Entra app registrations
36
+ Retrieve a list of Entra app registrations.
28
37
 
29
38
  ```sh
30
39
  m365 entra app list
31
40
  ```
32
41
 
42
+ Retrieve a list of Entra app registrations with specified properties.
43
+
44
+ ```sh
45
+ m365 entra app list --properties "appId,displayName"
46
+ ```
47
+
33
48
  ## Response
34
49
 
35
50
  <Tabs>