@pnp/cli-microsoft365 7.7.0 → 7.8.0-beta.4a6e6f7

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 (67) hide show
  1. package/allCommands.json +1 -1
  2. package/allCommandsFull.json +1 -1
  3. package/dist/cli/cli.js +21 -9
  4. package/dist/index.js +13 -12
  5. package/dist/m365/cli/commands/config/config-set.js +4 -0
  6. package/dist/m365/commands/setup.js +3 -3
  7. package/dist/m365/entra/commands/app/app-permission-add.js +25 -6
  8. package/dist/m365/entra/commands/app/app-permission-list.js +17 -5
  9. package/dist/m365/entra/commands/group/group-add.js +12 -14
  10. package/dist/m365/entra/commands/group/group-user-add.js +6 -7
  11. package/dist/m365/entra/commands/m365group/m365group-add.js +4 -2
  12. package/dist/m365/entra/commands/user/user-registrationdetails-list.js +6 -7
  13. package/dist/m365/flow/commands/run/run-list.js +25 -0
  14. package/dist/m365/outlook/commands/message/message-list.js +87 -17
  15. package/dist/m365/planner/commands/bucket/bucket-add.js +4 -7
  16. package/dist/m365/planner/commands/bucket/bucket-get.js +7 -30
  17. package/dist/m365/planner/commands/bucket/bucket-list.js +3 -6
  18. package/dist/m365/planner/commands/bucket/bucket-remove.js +8 -25
  19. package/dist/m365/planner/commands/bucket/bucket-set.js +12 -34
  20. package/dist/m365/planner/commands/plan/plan-add.js +17 -7
  21. package/dist/m365/planner/commands/plan/plan-get.js +12 -22
  22. package/dist/m365/planner/commands/plan/plan-list.js +1 -2
  23. package/dist/m365/planner/commands/plan/plan-remove.js +5 -3
  24. package/dist/m365/planner/commands/plan/plan-set.js +18 -10
  25. package/dist/m365/planner/commands/roster/roster-add.js +1 -2
  26. package/dist/m365/planner/commands/task/task-add.js +15 -21
  27. package/dist/m365/planner/commands/task/task-checklistitem-add.js +1 -1
  28. package/dist/m365/planner/commands/task/task-checklistitem-remove.js +1 -1
  29. package/dist/m365/planner/commands/task/task-get.js +5 -26
  30. package/dist/m365/planner/commands/task/task-list.js +11 -37
  31. package/dist/m365/planner/commands/task/task-reference-remove.js +1 -1
  32. package/dist/m365/planner/commands/task/task-remove.js +12 -29
  33. package/dist/m365/planner/commands/task/task-set.js +15 -21
  34. package/dist/m365/spfx/commands/project/project-doctor/{doctor-1.19.0-beta.0.js → doctor-1.19.0.js} +1 -1
  35. package/dist/m365/spfx/commands/project/project-doctor.js +1 -1
  36. package/dist/m365/spfx/commands/project/project-upgrade/{upgrade-1.19.0-beta.0.js → upgrade-1.19.0.js} +22 -22
  37. package/dist/m365/spfx/commands/project/project-upgrade.js +13 -15
  38. package/dist/m365/spfx/commands/spfx-doctor.js +1 -1
  39. package/dist/m365/spo/commands/listitem/listitem-batch-remove.js +222 -0
  40. package/dist/m365/spo/commands/navigation/navigation-node-add.js +3 -2
  41. package/dist/m365/spo/commands/navigation/navigation-node-set.js +3 -2
  42. package/dist/m365/spo/commands/site/site-add.js +17 -26
  43. package/dist/m365/spo/commands/site/site-recyclebinitem-move.js +5 -2
  44. package/dist/m365/spo/commands/site/site-recyclebinitem-remove.js +3 -2
  45. package/dist/m365/spo/commands/site/site-remove.js +129 -159
  46. package/dist/m365/spo/commands/site/site-set.js +9 -13
  47. package/dist/m365/spo/commands/spo-set.js +6 -2
  48. package/dist/m365/spo/commands/tenant/tenant-recyclebinitem-remove.js +9 -13
  49. package/dist/m365/spo/commands.js +1 -0
  50. package/dist/m365/teams/commands/meeting/meeting-add.js +3 -3
  51. package/dist/m365/teams/commands/team/team-add.js +22 -16
  52. package/dist/settingsNames.js +1 -0
  53. package/dist/utils/planner.js +87 -8
  54. package/dist/utils/spo.js +209 -278
  55. package/dist/utils/urlUtil.js +8 -0
  56. package/dist/utils/validation.js +8 -5
  57. package/docs/docs/_clisettings.mdx +1 -0
  58. package/docs/docs/cmd/entra/app/app-permission-add.mdx +7 -4
  59. package/docs/docs/cmd/entra/app/app-permission-list.mdx +14 -5
  60. package/docs/docs/cmd/entra/m365group/m365group-add.mdx +24 -24
  61. package/docs/docs/cmd/flow/run/run-list.mdx +74 -1
  62. package/docs/docs/cmd/outlook/message/message-list.mdx +18 -6
  63. package/docs/docs/cmd/spfx/project/project-upgrade.mdx +1 -1
  64. package/docs/docs/cmd/spo/listitem/listitem-batch-remove.mdx +70 -0
  65. package/docs/docs/cmd/spo/site/site-remove.mdx +9 -19
  66. package/npm-shrinkwrap.json +170 -230
  67. package/package.json +17 -17
@@ -3,17 +3,17 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
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
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _SpoSiteRemoveCommand_instances, _SpoSiteRemoveCommand_initTelemetry, _SpoSiteRemoveCommand_initOptions, _SpoSiteRemoveCommand_initValidators;
7
- import chalk from 'chalk';
6
+ var _SpoSiteRemoveCommand_instances, _SpoSiteRemoveCommand_initTelemetry, _SpoSiteRemoveCommand_initOptions, _SpoSiteRemoveCommand_initValidators, _SpoSiteRemoveCommand_initTypes;
8
7
  import { cli } from '../../../../cli/cli.js';
9
- import config from '../../../../config.js';
10
8
  import request from '../../../../request.js';
11
- import { entraGroup } from '../../../../utils/entraGroup.js';
12
9
  import { formatting } from '../../../../utils/formatting.js';
13
- import { spo } from '../../../../utils/spo.js';
14
10
  import { validation } from '../../../../utils/validation.js';
15
11
  import SpoCommand from '../../../base/SpoCommand.js';
16
12
  import commands from '../../commands.js';
13
+ import { odata } from '../../../../utils/odata.js';
14
+ import { spo } from '../../../../utils/spo.js';
15
+ import { setTimeout } from 'timers/promises';
16
+ import { urlUtil } from '../../../../utils/urlUtil.js';
17
17
  class SpoSiteRemoveCommand extends SpoCommand {
18
18
  get name() {
19
19
  return commands.SITE_REMOVE;
@@ -24,227 +24,180 @@ class SpoSiteRemoveCommand extends SpoCommand {
24
24
  constructor() {
25
25
  super();
26
26
  _SpoSiteRemoveCommand_instances.add(this);
27
+ this.pollingInterval = 5000;
27
28
  __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initTelemetry).call(this);
28
29
  __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initOptions).call(this);
29
30
  __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initValidators).call(this);
31
+ __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initTypes).call(this);
30
32
  }
31
33
  async commandAction(logger, args) {
34
+ if (args.options.wait) {
35
+ await this.warn(logger, `Option 'wait' is deprecated and will be removed in the next major release.`);
36
+ }
32
37
  if (args.options.force) {
33
- await this.removeSite(logger, args);
38
+ await this.removeSite(logger, args.options);
34
39
  }
35
40
  else {
36
- const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove the site ${args.options.url}?` });
41
+ const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove the site '${args.options.url}'?` });
37
42
  if (result) {
38
- await this.removeSite(logger, args);
43
+ await this.removeSite(logger, args.options);
39
44
  }
40
45
  }
41
46
  }
42
- async removeSite(logger, args) {
47
+ async removeSite(logger, options) {
43
48
  try {
44
- if (args.options.fromRecycleBin) {
45
- await this.deleteSiteWithoutGroup(logger, args);
49
+ if (this.verbose) {
50
+ await logger.logToStderr(`Removing site '${options.url}'...`);
46
51
  }
47
- else {
48
- const groupId = await this.getSiteGroupId(args.options.url, logger);
49
- if (groupId === '00000000-0000-0000-0000-000000000000') {
50
- if (this.debug) {
51
- await logger.logToStderr('Site is not groupified. Going ahead with the conventional site deletion options');
52
- }
53
- await this.deleteSiteWithoutGroup(logger, args);
52
+ this.spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
53
+ const siteUrl = urlUtil.removeTrailingSlashes(options.url);
54
+ const siteDetails = await this.getSiteDetails(logger, siteUrl);
55
+ const isGroupSite = siteDetails.GroupId && siteDetails.GroupId !== '00000000-0000-0000-0000-000000000000';
56
+ if (options.fromRecycleBin) {
57
+ if (!siteDetails.TimeDeleted) {
58
+ throw `Site is currently not in the recycle bin. Remove --fromRecycleBin if you want to remove it as active site.`;
54
59
  }
55
- else {
56
- if (this.debug) {
57
- await logger.logToStderr(`Site attached to group ${groupId}. Initiating group delete operation via Graph API`);
60
+ if (isGroupSite) {
61
+ if (this.verbose) {
62
+ await logger.logToStderr(`Checking if group '${siteDetails.GroupId}' is already permanently deleted from recycle bin.`);
58
63
  }
59
- try {
60
- const group = await entraGroup.getGroupById(groupId);
61
- if (args.options.skipRecycleBin || args.options.wait) {
62
- await logger.logToStderr(chalk.yellow(`Entered site is a groupified site. Hence, the parameters 'skipRecycleBin' and 'wait' will not be applicable.`));
63
- }
64
- await this.deleteGroup(group.id, logger);
65
- await this.deleteSite(args.options.url, args.options.wait, logger);
64
+ const isGroupInRecycleBin = await this.isGroupInEntraRecycleBin(logger, siteDetails.GroupId);
65
+ if (isGroupInRecycleBin) {
66
+ await this.removeGroupFromEntraRecycleBin(logger, siteDetails.GroupId);
66
67
  }
67
- catch (err) {
68
- if (this.verbose) {
69
- await logger.logToStderr(`Site group doesn't exist. Searching in the Microsoft 365 deleted groups.`);
70
- }
71
- const deletedGroups = await this.isSiteGroupDeleted(groupId);
72
- if (deletedGroups.value.length === 0) {
73
- if (this.verbose) {
74
- await logger.logToStderr("Site group doesn't exist anymore. Deleting the site.");
75
- }
76
- if (args.options.wait) {
77
- await logger.logToStderr(chalk.yellow(`Entered site is a groupified site. Hence, the parameter 'wait' will not be applicable.`));
78
- }
79
- await this.deleteOrphanedSite(logger, args.options.url);
68
+ }
69
+ await this.deleteSiteFromSharePointRecycleBin(logger, siteUrl);
70
+ }
71
+ else {
72
+ if (siteDetails.TimeDeleted) {
73
+ throw `Site is already in the recycle bin. Use --fromRecycleBin to permanently delete it.`;
74
+ }
75
+ if (isGroupSite) {
76
+ await this.deleteGroupifiedSite(logger, siteUrl);
77
+ if (options.skipRecycleBin) {
78
+ let isGroupInRecycleBin = await this.isGroupInEntraRecycleBin(logger, siteDetails.GroupId);
79
+ let amountOfPolls = 0;
80
+ while (!isGroupInRecycleBin && amountOfPolls < 20) {
81
+ await setTimeout(this.pollingInterval);
82
+ isGroupInRecycleBin = await this.isGroupInEntraRecycleBin(logger, siteDetails.GroupId);
83
+ amountOfPolls++;
80
84
  }
81
- else {
82
- throw `Site group still exists in the deleted groups. The site won't be removed.`;
85
+ if (isGroupInRecycleBin) {
86
+ await this.removeGroupFromEntraRecycleBin(logger, siteDetails.GroupId);
83
87
  }
84
88
  }
85
89
  }
90
+ else {
91
+ await this.deleteNonGroupSite(logger, siteUrl);
92
+ }
93
+ if (options.skipRecycleBin) {
94
+ await this.deleteSiteFromSharePointRecycleBin(logger, siteUrl);
95
+ }
86
96
  }
87
97
  }
88
98
  catch (err) {
89
- this.handleRejectedPromise(err);
99
+ this.handleRejectedODataJsonPromise(err);
90
100
  }
91
101
  }
92
- isSiteGroupDeleted(groupId) {
102
+ async removeGroupFromEntraRecycleBin(logger, groupId) {
103
+ if (this.verbose) {
104
+ await logger.logToStderr(`Permanently deleting group '${groupId}'.`);
105
+ }
93
106
  const requestOptions = {
94
- url: `https://graph.microsoft.com/v1.0/directory/deletedItems/Microsoft.Graph.Group?$select=id&$filter=groupTypes/any(c:c+eq+'Unified') and startswith(id, '${groupId}')`,
107
+ url: `https://graph.microsoft.com/v1.0/directory/deletedItems/Microsoft.Graph.Group/${groupId}`,
95
108
  headers: {
96
109
  accept: 'application/json;odata.metadata=none'
97
110
  },
98
111
  responseType: 'json'
99
112
  };
100
- return request.get(requestOptions);
113
+ return request.delete(requestOptions);
101
114
  }
102
- async deleteOrphanedSite(logger, url) {
103
- const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
115
+ async isGroupInEntraRecycleBin(logger, groupId) {
116
+ if (this.verbose) {
117
+ await logger.logToStderr(`Checking if group '${groupId}' is in the Microsoft Entra recycle bin.`);
118
+ }
104
119
  const requestOptions = {
105
- url: `${spoAdminUrl}/_api/GroupSiteManager/Delete?siteUrl='${url}'`,
120
+ url: `https://graph.microsoft.com/v1.0/directory/deletedItems/Microsoft.Graph.Group/${groupId}?$select=id`,
106
121
  headers: {
107
- 'content-type': 'application/json;odata=nometadata',
108
- accept: 'application/json;odata=nometadata'
122
+ accept: 'application/json;odata.metadata=none'
109
123
  },
110
124
  responseType: 'json'
111
125
  };
112
- return await request.post(requestOptions);
113
- }
114
- async deleteSiteWithoutGroup(logger, args) {
115
- this.spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
116
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
117
- if (args.options.fromRecycleBin) {
118
- if (this.verbose) {
119
- await logger.logToStderr(`Deleting site from recycle bin ${args.options.url}...`);
120
- }
121
- await this.deleteSiteFromTheRecycleBin(args.options.url, args.options.wait, logger);
122
- }
123
- else {
124
- await this.deleteSite(args.options.url, args.options.wait, logger);
126
+ try {
127
+ await request.get(requestOptions);
128
+ return true;
125
129
  }
126
- if (args.options.skipRecycleBin) {
127
- if (this.verbose) {
128
- await logger.logToStderr(`Also deleting site from tenant recycle bin ${args.options.url}...`);
130
+ catch (err) {
131
+ if (err.response?.status === 404) {
132
+ return false;
129
133
  }
130
- await this.deleteSiteFromTheRecycleBin(args.options.url, args.options.wait, logger);
134
+ throw err;
131
135
  }
132
136
  }
133
- async deleteSite(url, wait, logger) {
134
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
137
+ async deleteNonGroupSite(logger, siteUrl) {
135
138
  if (this.verbose) {
136
- await logger.logToStderr(`Deleting site ${url}...`);
139
+ await logger.logToStderr(`Deleting site.`);
137
140
  }
138
141
  const requestOptions = {
139
- url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
142
+ url: `${this.spoAdminUrl}/_api/Microsoft.Online.SharePoint.TenantAdministration.Tenant/RemoveSite`,
140
143
  headers: {
141
- 'X-RequestDigest': this.context.FormDigestValue
144
+ accept: 'application/json;odata=nometadata'
142
145
  },
143
- 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="55" ObjectPathId="54"/><ObjectPath Id="57" ObjectPathId="56"/><Query Id="58" ObjectPathId="54"><Query SelectAllProperties="true"><Properties/></Query></Query><Query Id="59" ObjectPathId="56"><Query SelectAllProperties="false"><Properties><Property Name="IsComplete" ScalarProperty="true"/><Property Name="PollingInterval" ScalarProperty="true"/></Properties></Query></Query></Actions><ObjectPaths><Constructor Id="54" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}"/><Method Id="56" ParentId="54" Name="RemoveSite"><Parameters><Parameter Type="String">${formatting.escapeXml(url)}</Parameter></Parameters></Method></ObjectPaths></Request>`
144
- };
145
- const response = await request.post(requestOptions);
146
- const json = JSON.parse(response);
147
- const responseContent = json[0];
148
- if (responseContent.ErrorInfo) {
149
- throw responseContent.ErrorInfo.ErrorMessage;
150
- }
151
- const operation = json[json.length - 1];
152
- const isComplete = operation.IsComplete;
153
- if (!wait || isComplete) {
154
- return;
155
- }
156
- await new Promise((resolve, reject) => {
157
- setTimeout(() => {
158
- spo.waitUntilFinished({
159
- operationId: JSON.stringify(operation._ObjectIdentity_),
160
- siteUrl: this.spoAdminUrl,
161
- resolve,
162
- reject,
163
- logger,
164
- currentContext: this.context,
165
- debug: this.debug,
166
- verbose: this.verbose
167
- });
168
- }, operation.PollingInterval);
169
- });
170
- }
171
- async deleteSiteFromTheRecycleBin(url, wait, logger) {
172
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
173
- const requestOptions = {
174
- url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
175
- headers: {
176
- 'X-RequestDigest': this.context.FormDigestValue
146
+ data: {
147
+ siteUrl: siteUrl
177
148
  },
178
- 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="185" ObjectPathId="184" /><Query Id="186" ObjectPathId="184"><Query SelectAllProperties="false"><Properties><Property Name="IsComplete" ScalarProperty="true" /><Property Name="PollingInterval" ScalarProperty="true" /></Properties></Query></Query></Actions><ObjectPaths><Method Id="184" ParentId="175" Name="RemoveDeletedSite"><Parameters><Parameter Type="String">${formatting.escapeXml(url)}</Parameter></Parameters></Method><Constructor Id="175" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}" /></ObjectPaths></Request>`
149
+ responseType: 'json'
179
150
  };
180
- const response = await request.post(requestOptions);
181
- const json = JSON.parse(response);
182
- const responseContent = json[0];
183
- if (responseContent.ErrorInfo) {
184
- throw responseContent.ErrorInfo.ErrorMessage;
185
- }
186
- const operation = json[json.length - 1];
187
- const isComplete = operation.IsComplete;
188
- if (!wait || isComplete) {
189
- return;
190
- }
191
- await new Promise((resolve, reject) => {
192
- setTimeout(() => {
193
- spo.waitUntilFinished({
194
- operationId: JSON.stringify(operation._ObjectIdentity_),
195
- siteUrl: this.spoAdminUrl,
196
- resolve,
197
- reject,
198
- logger,
199
- currentContext: this.context,
200
- debug: this.debug,
201
- verbose: this.verbose
202
- });
203
- }, operation.PollingInterval);
204
- });
151
+ return request.post(requestOptions);
205
152
  }
206
- async getSiteGroupId(url, logger) {
207
- this.spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
208
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
153
+ async deleteSiteFromSharePointRecycleBin(logger, url) {
209
154
  if (this.verbose) {
210
- await logger.logToStderr(`Retrieving the group Id of the site ${url}`);
155
+ await logger.logToStderr(`Permanently deleting site from the recycle bin.`);
211
156
  }
212
157
  const requestOptions = {
213
- url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
158
+ url: `${this.spoAdminUrl}/_api/Microsoft.Online.SharePoint.TenantAdministration.Tenant/RemoveDeletedSite`,
214
159
  headers: {
215
- 'X-RequestDigest': this.context.FormDigestValue
160
+ accept: 'application/json;odata=nometadata',
161
+ 'Content-Type': 'application/json'
216
162
  },
217
- data: `<Request xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009" AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="16.0.0.0" ApplicationName="${config.applicationName}"><Actions><ObjectPath Id="4" ObjectPathId="3"/><Query Id="5" ObjectPathId="3"><Query SelectAllProperties="false"><Properties><Property Name="GroupId" ScalarProperty="true"/></Properties></Query></Query></Actions><ObjectPaths><Constructor Id="1" TypeId="{268004ae-ef6b-4e9b-8425-127220d84719}"/><Method Id="3" ParentId="1" Name="GetSitePropertiesByUrl"><Parameters><Parameter Type="String">${formatting.escapeXml(url)}</Parameter></Parameters></Method></ObjectPaths></Request>`
163
+ data: {
164
+ siteUrl: url
165
+ },
166
+ responseType: 'json'
218
167
  };
219
- const response = await request.post(requestOptions);
220
- const json = JSON.parse(response);
221
- const responseContent = json[0];
222
- if (responseContent.ErrorInfo) {
223
- throw responseContent.ErrorInfo.ErrorMessage;
168
+ return request.post(requestOptions);
169
+ }
170
+ async getSiteDetails(logger, url) {
171
+ if (this.verbose) {
172
+ await logger.logToStderr(`Retrieving site info.`);
224
173
  }
225
- const groupId = json[json.length - 1].GroupId.replace('/Guid(', '').replace(')/', '');
226
- return groupId;
174
+ const sites = await odata.getAllItems(`${this.spoAdminUrl}/_api/web/lists/GetByTitle('DO_NOT_DELETE_SPLIST_TENANTADMIN_AGGREGATED_SITECOLLECTIONS')/items?$filter=SiteUrl eq '${formatting.encodeQueryParameter(url)}'&$select=GroupId,TimeDeleted,SiteId`);
175
+ if (sites.length === 0) {
176
+ throw `Site not found in the tenant.`;
177
+ }
178
+ return sites[0];
227
179
  }
228
- async deleteGroup(groupId, logger) {
180
+ async deleteGroupifiedSite(logger, siteUrl) {
229
181
  if (this.verbose) {
230
- await logger.logToStderr(`Removing Microsoft 365 Group: ${groupId}...`);
182
+ await logger.logToStderr(`Removing groupified site.`);
231
183
  }
232
184
  const requestOptions = {
233
- url: `https://graph.microsoft.com/v1.0/groups/${groupId}`,
185
+ url: `${this.spoAdminUrl}/_api/GroupSiteManager/Delete?siteUrl='${formatting.encodeQueryParameter(siteUrl)}'`,
234
186
  headers: {
235
- 'accept': 'application/json;odata.metadata=none'
236
- }
187
+ accept: 'application/json;odata=nometadata'
188
+ },
189
+ responseType: 'json'
237
190
  };
238
- return request.delete(requestOptions);
191
+ return request.post(requestOptions);
239
192
  }
240
193
  }
241
194
  _SpoSiteRemoveCommand_instances = new WeakSet(), _SpoSiteRemoveCommand_initTelemetry = function _SpoSiteRemoveCommand_initTelemetry() {
242
195
  this.telemetry.push((args) => {
243
196
  Object.assign(this.telemetryProperties, {
244
- skipRecycleBin: (!(!args.options.skipRecycleBin)).toString(),
245
- fromRecycleBin: (!(!args.options.fromRecycleBin)).toString(),
246
- wait: args.options.wait,
247
- force: (!(!args.options.force)).toString()
197
+ skipRecycleBin: !!args.options.skipRecycleBin,
198
+ fromRecycleBin: !!args.options.fromRecycleBin,
199
+ wait: !!args.options.wait,
200
+ force: !!args.options.force
248
201
  });
249
202
  });
250
203
  }, _SpoSiteRemoveCommand_initOptions = function _SpoSiteRemoveCommand_initOptions() {
@@ -260,7 +213,24 @@ _SpoSiteRemoveCommand_instances = new WeakSet(), _SpoSiteRemoveCommand_initTelem
260
213
  option: '-f, --force'
261
214
  });
262
215
  }, _SpoSiteRemoveCommand_initValidators = function _SpoSiteRemoveCommand_initValidators() {
263
- this.validators.push(async (args) => validation.isValidSharePointUrl(args.options.url));
216
+ this.validators.push(async (args) => {
217
+ const isValidSharePointUrl = validation.isValidSharePointUrl(args.options.url);
218
+ if (isValidSharePointUrl !== true) {
219
+ return isValidSharePointUrl;
220
+ }
221
+ const uri = new URL(args.options.url);
222
+ const rootUrl = `${uri.protocol}//${uri.hostname}`;
223
+ if (rootUrl.toLowerCase() === urlUtil.removeTrailingSlashes(args.options.url.toLowerCase())) {
224
+ return `The root site cannot be deleted.`;
225
+ }
226
+ if (args.options.fromRecycleBin && args.options.skipRecycleBin) {
227
+ return 'Specify either fromRecycleBin or skipRecycleBin, but not both.';
228
+ }
229
+ return true;
230
+ });
231
+ }, _SpoSiteRemoveCommand_initTypes = function _SpoSiteRemoveCommand_initTypes() {
232
+ this.types.string.push('url');
233
+ this.types.boolean.push('skipRecycleBin', 'fromRecycleBin', 'wait', 'force');
264
234
  };
265
235
  export default new SpoSiteRemoveCommand();
266
236
  //# sourceMappingURL=site-remove.js.map
@@ -18,6 +18,7 @@ import commands from '../../commands.js';
18
18
  import { SharingCapabilities } from '../site/SharingCapabilities.js';
19
19
  import spoSiteDesignApplyCommand from '../sitedesign/sitedesign-apply.js';
20
20
  import { FlowsPolicy } from './FlowsPolicy.js';
21
+ import { setTimeout } from 'timers/promises';
21
22
  class SpoSiteSetCommand extends SpoCommand {
22
23
  get name() {
23
24
  return commands.SITE_SET;
@@ -128,19 +129,14 @@ class SpoSiteSetCommand extends SpoCommand {
128
129
  if (!args.options.wait || isComplete) {
129
130
  return;
130
131
  }
131
- await new Promise((resolve, reject) => {
132
- setTimeout(() => {
133
- spo.waitUntilFinished({
134
- operationId: JSON.stringify(operation._ObjectIdentity_),
135
- siteUrl: this.spoAdminUrl,
136
- resolve,
137
- reject,
138
- logger,
139
- currentContext: this.context,
140
- debug: this.debug,
141
- verbose: this.verbose
142
- });
143
- }, operation.PollingInterval);
132
+ await setTimeout(operation.PollingInterval);
133
+ await spo.waitUntilFinished({
134
+ operationId: JSON.stringify(operation._ObjectIdentity_),
135
+ siteUrl: this.spoAdminUrl,
136
+ logger,
137
+ currentContext: this.context,
138
+ debug: this.debug,
139
+ verbose: this.verbose
144
140
  });
145
141
  }
146
142
  async updateSiteOwners(logger, args) {
@@ -3,8 +3,9 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
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
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _SpoSetCommand_instances, _SpoSetCommand_initOptions, _SpoSetCommand_initValidators;
6
+ var _SpoSetCommand_instances, _SpoSetCommand_initOptions, _SpoSetCommand_initValidators, _SpoSetCommand_initTypes;
7
7
  import auth from '../../../Auth.js';
8
+ import { urlUtil } from '../../../utils/urlUtil.js';
8
9
  import { validation } from '../../../utils/validation.js';
9
10
  import SpoCommand from '../../base/SpoCommand.js';
10
11
  import commands from '../commands.js';
@@ -20,9 +21,10 @@ class SpoSetCommand extends SpoCommand {
20
21
  _SpoSetCommand_instances.add(this);
21
22
  __classPrivateFieldGet(this, _SpoSetCommand_instances, "m", _SpoSetCommand_initOptions).call(this);
22
23
  __classPrivateFieldGet(this, _SpoSetCommand_instances, "m", _SpoSetCommand_initValidators).call(this);
24
+ __classPrivateFieldGet(this, _SpoSetCommand_instances, "m", _SpoSetCommand_initTypes).call(this);
23
25
  }
24
26
  async commandAction(logger, args) {
25
- auth.connection.spoUrl = args.options.url;
27
+ auth.connection.spoUrl = urlUtil.removeTrailingSlashes(args.options.url);
26
28
  try {
27
29
  await auth.storeConnectionInfo();
28
30
  }
@@ -37,6 +39,8 @@ _SpoSetCommand_instances = new WeakSet(), _SpoSetCommand_initOptions = function
37
39
  });
38
40
  }, _SpoSetCommand_initValidators = function _SpoSetCommand_initValidators() {
39
41
  this.validators.push(async (args) => validation.isValidSharePointUrl(args.options.url));
42
+ }, _SpoSetCommand_initTypes = function _SpoSetCommand_initTypes() {
43
+ this.types.string.push('url');
40
44
  };
41
45
  export default new SpoSetCommand();
42
46
  //# sourceMappingURL=spo-set.js.map
@@ -4,6 +4,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _SpoTenantRecycleBinItemRemoveCommand_instances, _SpoTenantRecycleBinItemRemoveCommand_initTelemetry, _SpoTenantRecycleBinItemRemoveCommand_initOptions, _SpoTenantRecycleBinItemRemoveCommand_initValidators;
7
+ import { setTimeout } from 'timers/promises';
7
8
  import { cli } from '../../../../cli/cli.js';
8
9
  import config from '../../../../config.js';
9
10
  import request from '../../../../request.js';
@@ -62,19 +63,14 @@ class SpoTenantRecycleBinItemRemoveCommand extends SpoCommand {
62
63
  if (!args.options.wait || isComplete) {
63
64
  return;
64
65
  }
65
- await new Promise((resolve, reject) => {
66
- setTimeout(() => {
67
- spo.waitUntilFinished({
68
- operationId: JSON.stringify(operation._ObjectIdentity_),
69
- siteUrl: spoAdminUrl,
70
- resolve,
71
- reject,
72
- logger,
73
- currentContext: this.context,
74
- debug: this.debug,
75
- verbose: this.verbose
76
- });
77
- }, operation.PollingInterval);
66
+ await setTimeout(operation.PollingInterval);
67
+ await spo.waitUntilFinished({
68
+ operationId: JSON.stringify(operation._ObjectIdentity_),
69
+ siteUrl: spoAdminUrl,
70
+ logger,
71
+ currentContext: this.context,
72
+ debug: this.debug,
73
+ verbose: this.verbose
78
74
  });
79
75
  }
80
76
  catch (err) {
@@ -164,6 +164,7 @@ export default {
164
164
  LISTITEM_ATTACHMENT_REMOVE: `${prefix} listitem attachment remove`,
165
165
  LISTITEM_ATTACHMENT_SET: `${prefix} listitem attachment set`,
166
166
  LISTITEM_BATCH_ADD: `${prefix} listitem batch add`,
167
+ LISTITEM_BATCH_REMOVE: `${prefix} listitem batch remove`,
167
168
  LISTITEM_BATCH_SET: `${prefix} listitem batch set`,
168
169
  LISTITEM_GET: `${prefix} listitem get`,
169
170
  LISTITEM_ISRECORD: `${prefix} listitem isrecord`,
@@ -136,9 +136,9 @@ _TeamsMeetingAddCommand_instances = new WeakSet(), _TeamsMeetingAddCommand_initT
136
136
  return 'The endTime value must be in the future.';
137
137
  }
138
138
  if (args.options.participantUserNames) {
139
- const participants = args.options.participantUserNames.trim().toLowerCase().split(',').filter(e => e && e !== '');
140
- if (!participants || participants.length === 0 || participants.some(e => !validation.isValidUserPrincipalName(e))) {
141
- return `'${args.options.participantUserNames}' contains one or more invalid UPN.`;
139
+ const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.participantUserNames);
140
+ if (isValidUPNArrayResult !== true) {
141
+ return `The following user principal names are invalid for the option 'participantUserNames': ${isValidUPNArrayResult}.`;
142
142
  }
143
143
  }
144
144
  if (args.options.organizerEmail && !validation.isValidUserPrincipalName(args.options.organizerEmail)) {
@@ -226,34 +226,40 @@ _TeamsTeamAddCommand_instances = new WeakSet(), _TeamsTeamAddCommand_initTelemet
226
226
  }, _TeamsTeamAddCommand_initValidators = function _TeamsTeamAddCommand_initValidators() {
227
227
  this.validators.push(async (args) => {
228
228
  if (args.options.ownerUserNames) {
229
- const isValidUserPrincipalNameArray = validation.isValidUserPrincipalNameArray(formatting.splitAndTrim(args.options.ownerUserNames));
230
- if (isValidUserPrincipalNameArray !== true) {
231
- return `Owner username '${isValidUserPrincipalNameArray}' is invalid for option 'ownerUserNames'.`;
229
+ const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.ownerUserNames);
230
+ if (isValidUPNArrayResult !== true) {
231
+ return `The following user principal names are invalid for the option 'ownerUserNames': ${isValidUPNArrayResult}.`;
232
232
  }
233
233
  }
234
234
  if (args.options.ownerEmails) {
235
- const isValidUserPrincipalNameArray = validation.isValidUserPrincipalNameArray(formatting.splitAndTrim(args.options.ownerEmails));
236
- if (isValidUserPrincipalNameArray !== true) {
237
- return `Owner email '${isValidUserPrincipalNameArray}' is invalid for option 'ownerEmails'.`;
235
+ const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.ownerEmails);
236
+ if (isValidUPNArrayResult !== true) {
237
+ return `The following user principal names are invalid for the option 'ownerEmails': ${isValidUPNArrayResult}.`;
238
238
  }
239
239
  }
240
- if (args.options.ownerIds && !validation.isValidGuidArray(formatting.splitAndTrim(args.options.ownerIds))) {
241
- return `The option 'ownerIds' contains one or more invalid GUIDs.`;
240
+ if (args.options.ownerIds) {
241
+ const isValidGUIDArrayResult = validation.isValidGuidArray(args.options.ownerIds);
242
+ if (isValidGUIDArrayResult !== true) {
243
+ return `The following GUIDs are invalid for the option 'ownerIds': ${isValidGUIDArrayResult}.`;
244
+ }
242
245
  }
243
246
  if (args.options.memberUserNames) {
244
- const isValidUserPrincipalNameArray = validation.isValidUserPrincipalNameArray(formatting.splitAndTrim(args.options.memberUserNames));
245
- if (isValidUserPrincipalNameArray !== true) {
246
- return `Member username '${isValidUserPrincipalNameArray}' is invalid for option 'memberUserNames'.`;
247
+ const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.memberUserNames);
248
+ if (isValidUPNArrayResult !== true) {
249
+ return `The following user principal names are invalid for the option 'memberUserNames': ${isValidUPNArrayResult}.`;
247
250
  }
248
251
  }
249
252
  if (args.options.memberEmails) {
250
- const isValidUserPrincipalNameArray = validation.isValidUserPrincipalNameArray(formatting.splitAndTrim(args.options.memberEmails));
251
- if (isValidUserPrincipalNameArray !== true) {
252
- return `Member email '${isValidUserPrincipalNameArray}' is invalid for option 'memberEmails'.`;
253
+ const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.memberEmails);
254
+ if (isValidUPNArrayResult !== true) {
255
+ return `The following user principal names are invalid for the option 'memberEmails': ${isValidUPNArrayResult}.`;
253
256
  }
254
257
  }
255
- if (args.options.memberIds && !validation.isValidGuidArray(formatting.splitAndTrim(args.options.memberIds))) {
256
- return `The option 'memberIds' contains one or more invalid GUIDs`;
258
+ if (args.options.memberIds) {
259
+ const isValidGUIDArrayResult = validation.isValidGuidArray(args.options.memberIds);
260
+ if (isValidGUIDArrayResult !== true) {
261
+ return `The following GUIDs are invalid for the option 'memberIds': ${isValidGUIDArrayResult}.`;
262
+ }
257
263
  }
258
264
  return true;
259
265
  });
@@ -10,6 +10,7 @@ const settingsNames = {
10
10
  disableTelemetry: 'disableTelemetry',
11
11
  errorOutput: 'errorOutput',
12
12
  helpMode: 'helpMode',
13
+ helpTarget: 'helpTarget',
13
14
  output: 'output',
14
15
  printErrorsAsPlainText: 'printErrorsAsPlainText',
15
16
  prompt: 'prompt',