@pnp/cli-microsoft365 7.8.0-beta.5ca5055 → 7.8.0-beta.5f64790

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.
@@ -3,18 +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';
17
15
  import { setTimeout } from 'timers/promises';
16
+ import { urlUtil } from '../../../../utils/urlUtil.js';
18
17
  class SpoSiteRemoveCommand extends SpoCommand {
19
18
  get name() {
20
19
  return commands.SITE_REMOVE;
@@ -25,217 +24,180 @@ class SpoSiteRemoveCommand extends SpoCommand {
25
24
  constructor() {
26
25
  super();
27
26
  _SpoSiteRemoveCommand_instances.add(this);
27
+ this.pollingInterval = 5000;
28
28
  __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initTelemetry).call(this);
29
29
  __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initOptions).call(this);
30
30
  __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initValidators).call(this);
31
+ __classPrivateFieldGet(this, _SpoSiteRemoveCommand_instances, "m", _SpoSiteRemoveCommand_initTypes).call(this);
31
32
  }
32
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
+ }
33
37
  if (args.options.force) {
34
- await this.removeSite(logger, args);
38
+ await this.removeSite(logger, args.options);
35
39
  }
36
40
  else {
37
- 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}'?` });
38
42
  if (result) {
39
- await this.removeSite(logger, args);
43
+ await this.removeSite(logger, args.options);
40
44
  }
41
45
  }
42
46
  }
43
- async removeSite(logger, args) {
47
+ async removeSite(logger, options) {
44
48
  try {
45
- if (args.options.fromRecycleBin) {
46
- await this.deleteSiteWithoutGroup(logger, args);
49
+ if (this.verbose) {
50
+ await logger.logToStderr(`Removing site '${options.url}'...`);
47
51
  }
48
- else {
49
- const groupId = await this.getSiteGroupId(args.options.url, logger);
50
- if (groupId === '00000000-0000-0000-0000-000000000000') {
51
- if (this.debug) {
52
- await logger.logToStderr('Site is not groupified. Going ahead with the conventional site deletion options');
53
- }
54
- 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.`;
55
59
  }
56
- else {
57
- if (this.debug) {
58
- 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.`);
59
63
  }
60
- try {
61
- const group = await entraGroup.getGroupById(groupId);
62
- if (args.options.skipRecycleBin || args.options.wait) {
63
- await logger.logToStderr(chalk.yellow(`Entered site is a groupified site. Hence, the parameters 'skipRecycleBin' and 'wait' will not be applicable.`));
64
- }
65
- await this.deleteGroup(group.id, logger);
66
- 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);
67
67
  }
68
- catch (err) {
69
- if (this.verbose) {
70
- await logger.logToStderr(`Site group doesn't exist. Searching in the Microsoft 365 deleted groups.`);
71
- }
72
- const deletedGroups = await this.isSiteGroupDeleted(groupId);
73
- if (deletedGroups.value.length === 0) {
74
- if (this.verbose) {
75
- await logger.logToStderr("Site group doesn't exist anymore. Deleting the site.");
76
- }
77
- if (args.options.wait) {
78
- await logger.logToStderr(chalk.yellow(`Entered site is a groupified site. Hence, the parameter 'wait' will not be applicable.`));
79
- }
80
- 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++;
81
84
  }
82
- else {
83
- 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);
84
87
  }
85
88
  }
86
89
  }
90
+ else {
91
+ await this.deleteNonGroupSite(logger, siteUrl);
92
+ }
93
+ if (options.skipRecycleBin) {
94
+ await this.deleteSiteFromSharePointRecycleBin(logger, siteUrl);
95
+ }
87
96
  }
88
97
  }
89
98
  catch (err) {
90
- this.handleRejectedPromise(err);
99
+ this.handleRejectedODataJsonPromise(err);
91
100
  }
92
101
  }
93
- isSiteGroupDeleted(groupId) {
102
+ async removeGroupFromEntraRecycleBin(logger, groupId) {
103
+ if (this.verbose) {
104
+ await logger.logToStderr(`Permanently deleting group '${groupId}'.`);
105
+ }
94
106
  const requestOptions = {
95
- 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}`,
96
108
  headers: {
97
109
  accept: 'application/json;odata.metadata=none'
98
110
  },
99
111
  responseType: 'json'
100
112
  };
101
- return request.get(requestOptions);
113
+ return request.delete(requestOptions);
102
114
  }
103
- async deleteOrphanedSite(logger, url) {
104
- 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
+ }
105
119
  const requestOptions = {
106
- url: `${spoAdminUrl}/_api/GroupSiteManager/Delete?siteUrl='${url}'`,
120
+ url: `https://graph.microsoft.com/v1.0/directory/deletedItems/Microsoft.Graph.Group/${groupId}?$select=id`,
107
121
  headers: {
108
- 'content-type': 'application/json;odata=nometadata',
109
- accept: 'application/json;odata=nometadata'
122
+ accept: 'application/json;odata.metadata=none'
110
123
  },
111
124
  responseType: 'json'
112
125
  };
113
- return await request.post(requestOptions);
114
- }
115
- async deleteSiteWithoutGroup(logger, args) {
116
- this.spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
117
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
118
- if (args.options.fromRecycleBin) {
119
- if (this.verbose) {
120
- await logger.logToStderr(`Deleting site from recycle bin ${args.options.url}...`);
121
- }
122
- await this.deleteSiteFromTheRecycleBin(args.options.url, args.options.wait, logger);
123
- }
124
- else {
125
- await this.deleteSite(args.options.url, args.options.wait, logger);
126
+ try {
127
+ await request.get(requestOptions);
128
+ return true;
126
129
  }
127
- if (args.options.skipRecycleBin) {
128
- if (this.verbose) {
129
- 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;
130
133
  }
131
- await this.deleteSiteFromTheRecycleBin(args.options.url, args.options.wait, logger);
134
+ throw err;
132
135
  }
133
136
  }
134
- async deleteSite(url, wait, logger) {
135
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
137
+ async deleteNonGroupSite(logger, siteUrl) {
136
138
  if (this.verbose) {
137
- await logger.logToStderr(`Deleting site ${url}...`);
139
+ await logger.logToStderr(`Deleting site.`);
138
140
  }
139
141
  const requestOptions = {
140
- url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
142
+ url: `${this.spoAdminUrl}/_api/Microsoft.Online.SharePoint.TenantAdministration.Tenant/RemoveSite`,
141
143
  headers: {
142
- 'X-RequestDigest': this.context.FormDigestValue
144
+ accept: 'application/json;odata=nometadata'
143
145
  },
144
- 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>`
145
- };
146
- const response = await request.post(requestOptions);
147
- const json = JSON.parse(response);
148
- const responseContent = json[0];
149
- if (responseContent.ErrorInfo) {
150
- throw responseContent.ErrorInfo.ErrorMessage;
151
- }
152
- const operation = json[json.length - 1];
153
- const isComplete = operation.IsComplete;
154
- if (!wait || isComplete) {
155
- return;
156
- }
157
- await setTimeout(operation.PollingInterval);
158
- await spo.waitUntilFinished({
159
- operationId: JSON.stringify(operation._ObjectIdentity_),
160
- siteUrl: this.spoAdminUrl,
161
- logger,
162
- currentContext: this.context,
163
- debug: this.debug,
164
- verbose: this.verbose
165
- });
166
- }
167
- async deleteSiteFromTheRecycleBin(url, wait, logger) {
168
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
169
- const requestOptions = {
170
- url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
171
- headers: {
172
- 'X-RequestDigest': this.context.FormDigestValue
146
+ data: {
147
+ siteUrl: siteUrl
173
148
  },
174
- 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'
175
150
  };
176
- const response = await request.post(requestOptions);
177
- const json = JSON.parse(response);
178
- const responseContent = json[0];
179
- if (responseContent.ErrorInfo) {
180
- throw responseContent.ErrorInfo.ErrorMessage;
181
- }
182
- const operation = json[json.length - 1];
183
- const isComplete = operation.IsComplete;
184
- if (!wait || isComplete) {
185
- return;
186
- }
187
- await setTimeout(operation.PollingInterval);
188
- await spo.waitUntilFinished({
189
- operationId: JSON.stringify(operation._ObjectIdentity_),
190
- siteUrl: this.spoAdminUrl,
191
- logger,
192
- currentContext: this.context,
193
- debug: this.debug,
194
- verbose: this.verbose
195
- });
151
+ return request.post(requestOptions);
196
152
  }
197
- async getSiteGroupId(url, logger) {
198
- this.spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug);
199
- this.context = await spo.ensureFormDigest(this.spoAdminUrl, logger, this.context, this.debug);
153
+ async deleteSiteFromSharePointRecycleBin(logger, url) {
200
154
  if (this.verbose) {
201
- await logger.logToStderr(`Retrieving the group Id of the site ${url}`);
155
+ await logger.logToStderr(`Permanently deleting site from the recycle bin.`);
202
156
  }
203
157
  const requestOptions = {
204
- url: `${this.spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`,
158
+ url: `${this.spoAdminUrl}/_api/Microsoft.Online.SharePoint.TenantAdministration.Tenant/RemoveDeletedSite`,
205
159
  headers: {
206
- 'X-RequestDigest': this.context.FormDigestValue
160
+ accept: 'application/json;odata=nometadata',
161
+ 'Content-Type': 'application/json'
207
162
  },
208
- 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'
209
167
  };
210
- const response = await request.post(requestOptions);
211
- const json = JSON.parse(response);
212
- const responseContent = json[0];
213
- if (responseContent.ErrorInfo) {
214
- 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.`);
215
173
  }
216
- const groupId = json[json.length - 1].GroupId.replace('/Guid(', '').replace(')/', '');
217
- 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];
218
179
  }
219
- async deleteGroup(groupId, logger) {
180
+ async deleteGroupifiedSite(logger, siteUrl) {
220
181
  if (this.verbose) {
221
- await logger.logToStderr(`Removing Microsoft 365 Group: ${groupId}...`);
182
+ await logger.logToStderr(`Removing groupified site.`);
222
183
  }
223
184
  const requestOptions = {
224
- url: `https://graph.microsoft.com/v1.0/groups/${groupId}`,
185
+ url: `${this.spoAdminUrl}/_api/GroupSiteManager/Delete?siteUrl='${formatting.encodeQueryParameter(siteUrl)}'`,
225
186
  headers: {
226
- 'accept': 'application/json;odata.metadata=none'
227
- }
187
+ accept: 'application/json;odata=nometadata'
188
+ },
189
+ responseType: 'json'
228
190
  };
229
- return request.delete(requestOptions);
191
+ return request.post(requestOptions);
230
192
  }
231
193
  }
232
194
  _SpoSiteRemoveCommand_instances = new WeakSet(), _SpoSiteRemoveCommand_initTelemetry = function _SpoSiteRemoveCommand_initTelemetry() {
233
195
  this.telemetry.push((args) => {
234
196
  Object.assign(this.telemetryProperties, {
235
- skipRecycleBin: (!(!args.options.skipRecycleBin)).toString(),
236
- fromRecycleBin: (!(!args.options.fromRecycleBin)).toString(),
237
- wait: args.options.wait,
238
- 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
239
201
  });
240
202
  });
241
203
  }, _SpoSiteRemoveCommand_initOptions = function _SpoSiteRemoveCommand_initOptions() {
@@ -251,7 +213,24 @@ _SpoSiteRemoveCommand_instances = new WeakSet(), _SpoSiteRemoveCommand_initTelem
251
213
  option: '-f, --force'
252
214
  });
253
215
  }, _SpoSiteRemoveCommand_initValidators = function _SpoSiteRemoveCommand_initValidators() {
254
- 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');
255
234
  };
256
235
  export default new SpoSiteRemoveCommand();
257
236
  //# sourceMappingURL=site-remove.js.map
@@ -197,6 +197,14 @@ export const urlUtil = {
197
197
  const rootUrl = new URL(fullUrl);
198
198
  return rootUrl.origin;
199
199
  }
200
+ },
201
+ /**
202
+ * Removes trailing slashes from the URL.
203
+ * @param url The URL to process.
204
+ * @returns The URL without trailing slashes.
205
+ */
206
+ removeTrailingSlashes(url) {
207
+ return url.replace(/\/+$/, '');
200
208
  }
201
209
  };
202
210
  //# sourceMappingURL=urlUtil.js.map
@@ -22,37 +22,37 @@ m365 aad m365group add [options]
22
22
 
23
23
  ```md definition-list
24
24
  `-n, --displayName <displayName>`
25
- : Display name for the Microsoft 365 Group
26
-
27
- `-d, --description <description>`
28
- : Description for the Microsoft 365 Group
25
+ : Display name for the Microsoft 365 Group.
29
26
 
30
27
  `-m, --mailNickname <mailNickname>`
31
- : Name to use in the group e-mail (part before the `@`)
28
+ : Name to use in the group e-mail (part before the `@`).
29
+
30
+ `-d, --description [description]`
31
+ : Description for the Microsoft 365 Group.
32
32
 
33
33
  `--owners [owners]`
34
- : Comma-separated list of Microsoft 365 Group owners
34
+ : Comma-separated list of Microsoft 365 Group owners.
35
35
 
36
36
  `--members [members]`
37
- : Comma-separated list of Microsoft 365 Group members
37
+ : Comma-separated list of Microsoft 365 Group members.
38
38
 
39
39
  `--visibility [visibility]`
40
40
  : Specifies the group join policy and group content visibility for groups. Allowed values: `Private`, `Public`, or `HiddenMembership`. Defaults to `Public`.
41
41
 
42
42
  `--allowMembersToPost [allowMembersToPost]`
43
- : Set if only group members should be able to post conversations to the group
43
+ : Set if only group members should be able to post conversations to the group.
44
44
 
45
45
  `--hideGroupInOutlook [hideGroupInOutlook]`
46
- : Set to hide the group in Outlook experiences
46
+ : Set to hide the group in Outlook experiences.
47
47
 
48
48
  `--subscribeNewGroupMembers [subscribeNewGroupMembers]`
49
- : Set to subscribe all new group members to receive group conversation emails when new messages are posted in the group
49
+ : Set to subscribe all new group members to receive group conversation emails when new messages are posted in the group.
50
50
 
51
51
  `--welcomeEmailDisabled [welcomeEmailDisabled]`
52
- : Set to not send welcome emails to new group members
52
+ : Set to not send welcome emails to new group members.
53
53
 
54
54
  `-l, --logoPath [logoPath]`
55
- : Local path to the image file to use as group logo
55
+ : Local path to the image file to use as group logo.
56
56
  ```
57
57
 
58
58
  <Global />
@@ -74,25 +74,25 @@ HiddenMembership | Owner permission is needed to join the group. Guest users can
74
74
 
75
75
  ## Examples
76
76
 
77
- Create a public Microsoft 365 Group
77
+ Create a public Microsoft 365 Group.
78
78
 
79
79
  ```sh
80
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance
80
+ m365 entra m365group add --displayName Finance --mailNickname finance
81
81
  ```
82
82
 
83
- Create a private Microsoft 365 Group
83
+ Create a private Microsoft 365 Group.
84
84
 
85
85
  ```sh
86
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --visibility Private
86
+ m365 entra m365group add --displayName Finance --mailNickname finance --visibility Private
87
87
  ```
88
88
 
89
- Create a public Microsoft 365 Group and set specified users as its owners
89
+ Create a public Microsoft 365 Group with description and set specified users as its owners.
90
90
 
91
91
  ```sh
92
92
  m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --owners "DebraB@contoso.onmicrosoft.com,DiegoS@contoso.onmicrosoft.com"
93
93
  ```
94
94
 
95
- Create a public Microsoft 365 Group and set specified users as its members
95
+ Create a public Microsoft 365 Group with description and set specified users as its members.
96
96
 
97
97
  ```sh
98
98
  m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --members "DebraB@contoso.onmicrosoft.com,DiegoS@contoso.onmicrosoft.com"
@@ -101,31 +101,31 @@ m365 entra m365group add --displayName Finance --description "This is the Contos
101
101
  Create a public Microsoft 365 Group and allow only group members to be able to post conversations to the group.
102
102
 
103
103
  ```sh
104
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --allowMembersToPost
104
+ m365 entra m365group add --displayName Finance --mailNickname finance --allowMembersToPost
105
105
  ```
106
106
 
107
107
  Create a public Microsoft 365 Group and hide it from the Outlook experiences (web and client).
108
108
 
109
109
  ```sh
110
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --hideGroupInOutlook
110
+ m365 entra m365group add --displayName Finance --mailNickname finance --hideGroupInOutlook
111
111
  ```
112
112
 
113
113
  Create a public Microsoft 365 Group and subscribe all new group members to receive group conversation emails when new messages are posted in the group.
114
114
 
115
115
  ```sh
116
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --subscribeNewGroupMembers
116
+ m365 entra m365group add --displayName Finance --mailNickname finance --subscribeNewGroupMembers
117
117
  ```
118
118
 
119
119
  Create a public Microsoft 365 Group and set to not send welcome emails to new group members.
120
120
 
121
121
  ```sh
122
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --welcomeEmailDisabled
122
+ m365 entra m365group add --displayName Finance --mailNickname finance --welcomeEmailDisabled
123
123
  ```
124
124
 
125
- Create a public Microsoft 365 Group and set its logo
125
+ Create a public Microsoft 365 Group and set its logo.
126
126
 
127
127
  ```sh
128
- m365 entra m365group add --displayName Finance --description "This is the Contoso Finance Group. Please come here and check out the latest news, posts, files, and more." --mailNickname finance --logoPath images/logo.png
128
+ m365 entra m365group add --displayName Finance --mailNickname finance --logoPath images/logo.png
129
129
  ```
130
130
 
131
131
  ## Response
@@ -20,28 +20,40 @@ m365 outlook message list [options]
20
20
 
21
21
  `--folderId [folderId]`
22
22
  : ID of the folder from which to list messages.
23
+
24
+ `--startTime [startTime]`
25
+ : Time indicating the inclusive start of a time range when the message was received. This should be defined as a valid ISO 8601 string (2021-12-16T18:28:48.6964197Z).
26
+
27
+ `--endTime [endTime]`
28
+ : Time indicating the exclusive end of a time range when the message was received. This should be defined as a valid ISO 8601 string (2021-12-16T18:28:48.6964197Z).
29
+
30
+ `--userId [userId]`
31
+ : The Microsoft Entra user ID. Specify either `userId` or `userName`, not both. This option is required when using application permissions.
32
+
33
+ `--userName [userName]`
34
+ : User principal name of the user. Specify either `userId` or `userName`, not both. This option is required when using application permissions.
23
35
  ```
24
36
 
25
37
  <Global />
26
38
 
27
39
  ## Examples
28
40
 
29
- List all messages in the folder with the specified name.
41
+ List all messages from a folder with the specified name received within a specific time frame.
30
42
 
31
43
  ```sh
32
- m365 outlook message list --folderName Archive
44
+ m365 outlook message list --folderName Archive --startTime 2023-12-16T18:28:48.6964197Z --endTime 2024-02-01
33
45
  ```
34
46
 
35
- List all messages in the folder with the specified ID.
47
+ List all messages from a specific folder of a user specified by ID.
36
48
 
37
49
  ```sh
38
- m365 outlook message list --folderId AAMkAGVmMDEzMTM4LTZmYWUtNDdkNC1hMDZiLTU1OGY5OTZhYmY4OAAuAAAAAAAiQ8W967B7TKBjgx9rVEURAQAiIsqMbYjsT5e-T7KzowPTAAAAAAFNAAA=
50
+ m365 outlook message list --folderId AAMkAGVmMDEzMTM4LTZmYWUtNDdkNC1hMDZiLTU1OGY5OTZhYmY4OAAuAAAAAAAiQ8W967B7TKBjgx9rVEURAQAiIsqMbYjsT5e-T7KzowPTAAAAAAFNAAA= --userId 48d31887-5fad-4d73-a9f5-3c356e68a038
39
51
  ```
40
52
 
41
- List all messages in the folder with the specified well-known name.
53
+ List all messages from a folder of a user specified by UPN.
42
54
 
43
55
  ```sh
44
- m365 outlook message list --folderName inbox
56
+ m365 outlook message list --folderName inbox --userName john@contoso.com
45
57
  ```
46
58
 
47
59
  ## Response
@@ -14,63 +14,53 @@ m365 spo site remove [options]
14
14
 
15
15
  ```md definition-list
16
16
  `-u, --url <url>`
17
- : URL of the site to remove
17
+ : URL of the site.
18
18
 
19
19
  `--skipRecycleBin`
20
- : Set to directly remove the site without moving it to the Recycle Bin
20
+ : Set to directly remove the site without moving it to the recycle bin.
21
21
 
22
22
  `--fromRecycleBin`
23
- : Set to remove the site from the Recycle Bin
23
+ : Set to remove the site from the recycle bin.
24
24
 
25
25
  `--wait`
26
- : Wait for the site to be removed before completing the command
26
+ : (deprecated) Wait for the site to be removed before completing the command.
27
27
 
28
28
  `-f, --force`
29
- : Don't prompt for confirming removing the site
29
+ : Don't prompt for confirmation.
30
30
  ```
31
31
 
32
32
  <Global />
33
33
 
34
34
  ## Remarks
35
35
 
36
- Deleting a site collection is by default asynchronous and depending on the current state of Microsoft 365, might take up to few minutes. If you're building a script with steps that require the site to be fully deleted, you should use the `--wait` flag. When using this flag, the `spo site remove` command will keep running until it received confirmation from Microsoft 365 that the site has been fully deleted.
37
-
38
- If the site which you have selected to remove is groupified (Modern Team Site) and group exists, flags `--skipRecycleBin` and `--wait` will not be applicable. If the linked group still exists in the deleted groups, the site won't be removed. If the linked group is permanently deleted, the site will be removed like any classic site (except that flag `--wait` only will still not be applicable).
39
-
40
36
  If the argument `--fromRecycleBin` is passed, the selected site will be permanently removed even if it's a groupified one.
41
37
 
42
38
  :::info
43
39
 
44
- To use this command you have to have permissions to access the tenant admin site.
40
+ To use this command you must be a Global or SharePoint administrator.
45
41
 
46
42
  :::
47
43
 
48
44
  ## Examples
49
45
 
50
- Remove the specified site and place it in the Recycle Bin
46
+ Remove the specified site and place it in the recycle bin.
51
47
 
52
48
  ```sh
53
49
  m365 spo site remove --url https://contoso.sharepoint.com/sites/demosite
54
50
  ```
55
51
 
56
- Remove the site without moving it to the Recycle Bin
52
+ Remove the site without moving it to the recycle bin.
57
53
 
58
54
  ```sh
59
55
  m365 spo site remove --url https://contoso.sharepoint.com/sites/demosite --skipRecycleBin
60
56
  ```
61
57
 
62
- Remove the previously deleted site from the Recycle Bin
58
+ Remove the previously deleted site from the recycle bin.
63
59
 
64
60
  ```sh
65
61
  m365 spo site remove --url https://contoso.sharepoint.com/sites/demosite --fromRecycleBin
66
62
  ```
67
63
 
68
- Remove the site without moving it to the Recycle Bin and wait for completion
69
-
70
- ```sh
71
- m365 spo site remove --url https://contoso.sharepoint.com/sites/demosite --wait --skipRecycleBin
72
- ```
73
-
74
64
  ## Response
75
65
 
76
66
  The command won't return a response on success.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnp/cli-microsoft365",
3
- "version": "7.8.0-beta.5ca5055",
3
+ "version": "7.8.0-beta.5f64790",
4
4
  "description": "Manage Microsoft 365 and SharePoint Framework projects on any platform",
5
5
  "license": "MIT",
6
6
  "main": "./dist/api.js",