@pnp/cli-microsoft365 7.2.0 → 7.3.0-beta.01256d2

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 (69) hide show
  1. package/allCommands.json +1 -1
  2. package/allCommandsFull.json +1 -1
  3. package/dist/appInsights.js +2 -1
  4. package/dist/cli/Cli.js +14 -13
  5. package/dist/index.js +1 -9
  6. package/dist/m365/aad/commands/group/group-list.js +69 -1
  7. package/dist/m365/external/commands/connection/connection-doctor.js +424 -0
  8. package/dist/m365/external/commands/item/item-add.js +144 -0
  9. package/dist/m365/external/commands.js +3 -1
  10. package/dist/m365/teams/commands/meeting/meeting-add.js +151 -0
  11. package/dist/m365/teams/commands/user/user-app-remove.js +33 -2
  12. package/dist/m365/teams/commands.js +2 -1
  13. package/dist/telemetry.js +0 -8
  14. package/dist/utils/validation.js +5 -2
  15. package/docs/docs/cmd/aad/group/group-list.mdx +11 -0
  16. package/docs/docs/cmd/external/connection/connection-doctor.mdx +179 -0
  17. package/docs/docs/cmd/external/item/item-add.mdx +145 -0
  18. package/docs/docs/cmd/onedrive/report/report-activityfilecounts.mdx +0 -3
  19. package/docs/docs/cmd/onedrive/report/report-activityusercounts.mdx +0 -3
  20. package/docs/docs/cmd/onedrive/report/report-activityuserdetail.mdx +0 -3
  21. package/docs/docs/cmd/onedrive/report/report-usageaccountcounts.mdx +0 -3
  22. package/docs/docs/cmd/onedrive/report/report-usageaccountdetail.mdx +0 -3
  23. package/docs/docs/cmd/onedrive/report/report-usagefilecounts.mdx +0 -3
  24. package/docs/docs/cmd/onedrive/report/report-usagestorage.mdx +0 -3
  25. package/docs/docs/cmd/outlook/report/report-mailactivitycounts.mdx +0 -3
  26. package/docs/docs/cmd/outlook/report/report-mailactivityusercounts.mdx +0 -3
  27. package/docs/docs/cmd/outlook/report/report-mailactivityuserdetail.mdx +0 -3
  28. package/docs/docs/cmd/outlook/report/report-mailappusageappsusercounts.mdx +0 -3
  29. package/docs/docs/cmd/outlook/report/report-mailappusageusercounts.mdx +0 -3
  30. package/docs/docs/cmd/outlook/report/report-mailappusageuserdetail.mdx +0 -3
  31. package/docs/docs/cmd/outlook/report/report-mailappusageversionsusercounts.mdx +0 -3
  32. package/docs/docs/cmd/outlook/report/report-mailboxusagedetail.mdx +0 -3
  33. package/docs/docs/cmd/outlook/report/report-mailboxusagemailboxcount.mdx +0 -3
  34. package/docs/docs/cmd/outlook/report/report-mailboxusagequotastatusmailboxcounts.mdx +0 -3
  35. package/docs/docs/cmd/outlook/report/report-mailboxusagestorage.mdx +0 -3
  36. package/docs/docs/cmd/skype/report/report-activitycounts.mdx +0 -2
  37. package/docs/docs/cmd/skype/report/report-activityusercounts.mdx +0 -3
  38. package/docs/docs/cmd/skype/report/report-activityuserdetail.mdx +0 -3
  39. package/docs/docs/cmd/spo/report/report-activityfilecounts.mdx +0 -3
  40. package/docs/docs/cmd/spo/report/report-activitypages.mdx +0 -3
  41. package/docs/docs/cmd/spo/report/report-activityusercounts.mdx +0 -3
  42. package/docs/docs/cmd/spo/report/report-activityuserdetail.mdx +0 -3
  43. package/docs/docs/cmd/spo/report/report-siteusagedetail.mdx +0 -3
  44. package/docs/docs/cmd/spo/report/report-siteusagefilecounts.mdx +0 -3
  45. package/docs/docs/cmd/spo/report/report-siteusagepages.mdx +0 -3
  46. package/docs/docs/cmd/spo/report/report-siteusagesitecounts.mdx +0 -3
  47. package/docs/docs/cmd/spo/report/report-siteusagestorage.mdx +0 -3
  48. package/docs/docs/cmd/teams/meeting/meeting-add.mdx +283 -0
  49. package/docs/docs/cmd/teams/report/report-deviceusagedistributionusercounts.mdx +0 -3
  50. package/docs/docs/cmd/teams/report/report-deviceusageusercounts.mdx +0 -3
  51. package/docs/docs/cmd/teams/report/report-deviceusageuserdetail.mdx +0 -3
  52. package/docs/docs/cmd/teams/report/report-useractivitycounts.mdx +0 -3
  53. package/docs/docs/cmd/teams/report/report-useractivityusercounts.mdx +0 -3
  54. package/docs/docs/cmd/teams/report/report-useractivityuserdetail.mdx +0 -3
  55. package/docs/docs/cmd/teams/user/user-app-remove.mdx +13 -4
  56. package/docs/docs/cmd/tenant/report/report-activeusercounts.mdx +0 -3
  57. package/docs/docs/cmd/tenant/report/report-activeuserdetail.mdx +0 -3
  58. package/docs/docs/cmd/tenant/report/report-servicesusercounts.mdx +0 -3
  59. package/docs/docs/cmd/yammer/report/report-activitycounts.mdx +0 -3
  60. package/docs/docs/cmd/yammer/report/report-activityusercounts.mdx +0 -3
  61. package/docs/docs/cmd/yammer/report/report-activityuserdetail.mdx +0 -3
  62. package/docs/docs/cmd/yammer/report/report-deviceusagedistributionusercounts.mdx +0 -3
  63. package/docs/docs/cmd/yammer/report/report-deviceusageusercounts.mdx +0 -3
  64. package/docs/docs/cmd/yammer/report/report-deviceusageuserdetail.mdx +0 -3
  65. package/docs/docs/cmd/yammer/report/report-groupsactivitycounts.mdx +0 -3
  66. package/docs/docs/cmd/yammer/report/report-groupsactivitydetail.mdx +0 -3
  67. package/docs/docs/cmd/yammer/report/report-groupsactivitygroupcounts.mdx +0 -3
  68. package/npm-shrinkwrap.json +6 -6
  69. package/package.json +4 -3
@@ -0,0 +1,144 @@
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 _ExternalItemAddCommand_instances, _a, _ExternalItemAddCommand_initTelemetry, _ExternalItemAddCommand_initOptions, _ExternalItemAddCommand_initValidators;
7
+ import request from '../../../../request.js';
8
+ import GraphCommand from '../../../base/GraphCommand.js';
9
+ import commands from '../../commands.js';
10
+ class ExternalItemAddCommand extends GraphCommand {
11
+ get name() {
12
+ return commands.ITEM_ADD;
13
+ }
14
+ get description() {
15
+ return 'Creates external item';
16
+ }
17
+ constructor() {
18
+ super();
19
+ _ExternalItemAddCommand_instances.add(this);
20
+ __classPrivateFieldGet(this, _ExternalItemAddCommand_instances, "m", _ExternalItemAddCommand_initTelemetry).call(this);
21
+ __classPrivateFieldGet(this, _ExternalItemAddCommand_instances, "m", _ExternalItemAddCommand_initOptions).call(this);
22
+ __classPrivateFieldGet(this, _ExternalItemAddCommand_instances, "m", _ExternalItemAddCommand_initValidators).call(this);
23
+ }
24
+ allowUnknownOptions() {
25
+ return true;
26
+ }
27
+ async commandAction(logger, args) {
28
+ const acls = args.options.acls
29
+ .split(';')
30
+ .map(acl => {
31
+ const aclParts = acl.split(',');
32
+ return {
33
+ accessType: aclParts[0],
34
+ type: aclParts[1],
35
+ value: aclParts[2]
36
+ };
37
+ });
38
+ const requestBody = {
39
+ id: args.options.id,
40
+ content: {
41
+ value: args.options.content,
42
+ type: args.options.contentType ?? 'text'
43
+ },
44
+ acl: acls,
45
+ properties: {}
46
+ };
47
+ // we need to rewrite the @odata properties to the correct format
48
+ // because . in @odata.type is interpreted by minimist as a child property
49
+ // we also need to extract multiple values for collections into arrays
50
+ this.rewriteCollectionProperties(args.options);
51
+ this.addUnknownOptionsToPayload(requestBody.properties, args.options);
52
+ const requestOptions = {
53
+ url: `${this.resource}/v1.0/external/connections/${args.options.externalConnectionId}/items/${args.options.id}`,
54
+ headers: {
55
+ accept: 'application/json;odata.metadata=none',
56
+ 'content-type': 'application/json'
57
+ },
58
+ responseType: 'json',
59
+ data: requestBody
60
+ };
61
+ try {
62
+ const externalItem = await request.put(requestOptions);
63
+ if (args.options.output === 'csv' || args.options.output === 'md') {
64
+ // for CSV and md, we need to bring the properties to the main object
65
+ // and convert arrays to comma-separated strings or they will be dropped
66
+ // from the output
67
+ Object.getOwnPropertyNames(externalItem.properties).forEach(name => {
68
+ if (Array.isArray(externalItem.properties[name])) {
69
+ externalItem[name] = externalItem.properties[name].join(', ');
70
+ }
71
+ else {
72
+ externalItem[name] = externalItem.properties[name];
73
+ }
74
+ });
75
+ }
76
+ await logger.log(externalItem);
77
+ }
78
+ catch (err) {
79
+ this.handleRejectedODataJsonPromise(err);
80
+ }
81
+ }
82
+ rewriteCollectionProperties(options) {
83
+ Object.getOwnPropertyNames(options).forEach(name => {
84
+ if (!name.endsWith('@odata')) {
85
+ return;
86
+ }
87
+ options[`${name}.type`] = options[name].type;
88
+ delete options[name];
89
+ // convert the value of a collection to an array
90
+ const nameWithoutOData = name.substring(0, name.indexOf('@odata'));
91
+ if (options[nameWithoutOData]) {
92
+ options[nameWithoutOData] = options[nameWithoutOData].split(';#');
93
+ }
94
+ });
95
+ }
96
+ }
97
+ _a = ExternalItemAddCommand, _ExternalItemAddCommand_instances = new WeakSet(), _ExternalItemAddCommand_initTelemetry = function _ExternalItemAddCommand_initTelemetry() {
98
+ this.telemetry.push((args) => {
99
+ Object.assign(this.telemetryProperties, {
100
+ contentType: typeof args.options.contentType
101
+ });
102
+ });
103
+ }, _ExternalItemAddCommand_initOptions = function _ExternalItemAddCommand_initOptions() {
104
+ this.options.unshift({
105
+ option: '--id <id>'
106
+ }, {
107
+ option: '--externalConnectionId <externalConnectionId>'
108
+ }, {
109
+ option: '--content <content>'
110
+ }, {
111
+ option: '--contentType [contentType]',
112
+ autocomplete: _a.contentType
113
+ }, {
114
+ option: '--acls <acls>'
115
+ });
116
+ }, _ExternalItemAddCommand_initValidators = function _ExternalItemAddCommand_initValidators() {
117
+ this.validators.push(async (args) => {
118
+ if (args.options.contentType &&
119
+ _a.contentType.indexOf(args.options.contentType) < 0) {
120
+ return `${args.options.contentType} is not a valid value for contentType. Allowed values are ${_a.contentType.join(', ')}`;
121
+ }
122
+ // verify that each value for ACLs consists of three parts
123
+ // and that the values are correct
124
+ const acls = args.options.acls.split(';');
125
+ for (let i = 0; i < acls.length; i++) {
126
+ const acl = acls[i].split(',');
127
+ if (acl.length !== 3) {
128
+ return `The value ${acls[i]} for option acls is not in the correct format. The correct format is "accessType,type,value", eg. "grant,everyone,everyone"`;
129
+ }
130
+ const accessTypeValues = ['grant', 'deny'];
131
+ if (accessTypeValues.indexOf(acl[0]) < 0) {
132
+ return `The value ${acl[0]} for option acls is not valid. Allowed values are ${accessTypeValues.join(', ')}}`;
133
+ }
134
+ const aclTypeValues = ['user', 'group', 'everyone', 'everyoneExceptGuests', 'externalGroup'];
135
+ if (aclTypeValues.indexOf(acl[1]) < 0) {
136
+ return `The value ${acl[1]} for option acls is not valid. Allowed values are ${aclTypeValues.join(', ')}}`;
137
+ }
138
+ }
139
+ return true;
140
+ });
141
+ };
142
+ ExternalItemAddCommand.contentType = ['text', 'html'];
143
+ export default new ExternalItemAddCommand();
144
+ //# sourceMappingURL=item-add.js.map
@@ -2,6 +2,7 @@ const prefix = 'external';
2
2
  const searchPrefix = 'search';
3
3
  export default {
4
4
  CONNECTION_ADD: `${prefix} connection add`,
5
+ CONNECTION_DOCTOR: `${prefix} connection doctor`,
5
6
  CONNECTION_GET: `${prefix} connection get`,
6
7
  CONNECTION_LIST: `${prefix} connection list`,
7
8
  CONNECTION_REMOVE: `${prefix} connection remove`,
@@ -10,6 +11,7 @@ export default {
10
11
  EXTERNALCONNECTION_GET: `${searchPrefix} externalconnection get`,
11
12
  EXTERNALCONNECTION_LIST: `${searchPrefix} externalconnection list`,
12
13
  EXTERNALCONNECTION_REMOVE: `${searchPrefix} externalconnection remove`,
13
- EXTERNALCONNECTION_SCHEMA_ADD: `${searchPrefix} externalconnection schema add`
14
+ EXTERNALCONNECTION_SCHEMA_ADD: `${searchPrefix} externalconnection schema add`,
15
+ ITEM_ADD: `${prefix} item add`
14
16
  };
15
17
  //# sourceMappingURL=commands.js.map
@@ -0,0 +1,151 @@
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 _TeamsMeetingAddCommand_instances, _TeamsMeetingAddCommand_initTelemetry, _TeamsMeetingAddCommand_initOptions, _TeamsMeetingAddCommand_initValidators;
7
+ import auth from '../../../../Auth.js';
8
+ import { aadUser } from '../../../../utils/aadUser.js';
9
+ import { accessToken } from '../../../../utils/accessToken.js';
10
+ import { validation } from '../../../../utils/validation.js';
11
+ import GraphCommand from "../../../base/GraphCommand.js";
12
+ import commands from '../../commands.js';
13
+ import request from '../../../../request.js';
14
+ class TeamsMeetingAddCommand extends GraphCommand {
15
+ get name() {
16
+ return commands.MEETING_ADD;
17
+ }
18
+ get description() {
19
+ return 'Creates a new online meeting';
20
+ }
21
+ constructor() {
22
+ super();
23
+ _TeamsMeetingAddCommand_instances.add(this);
24
+ __classPrivateFieldGet(this, _TeamsMeetingAddCommand_instances, "m", _TeamsMeetingAddCommand_initTelemetry).call(this);
25
+ __classPrivateFieldGet(this, _TeamsMeetingAddCommand_instances, "m", _TeamsMeetingAddCommand_initOptions).call(this);
26
+ __classPrivateFieldGet(this, _TeamsMeetingAddCommand_instances, "m", _TeamsMeetingAddCommand_initValidators).call(this);
27
+ }
28
+ async commandAction(logger, args) {
29
+ try {
30
+ const isAppOnlyAccessToken = accessToken.isAppOnlyAccessToken(auth.service.accessTokens[this.resource].accessToken);
31
+ if (isAppOnlyAccessToken && !args.options.organizerEmail) {
32
+ throw `The option 'organizerEmail' is required when creating a meeting using app only permissions`;
33
+ }
34
+ if (!isAppOnlyAccessToken && args.options.organizerEmail) {
35
+ throw `The option 'organizerEmail' is not supported when creating a meeting using delegated permissions`;
36
+ }
37
+ const meeting = await this.createMeeting(logger, args.options);
38
+ await logger.log(meeting);
39
+ }
40
+ catch (err) {
41
+ this.handleRejectedODataJsonPromise(err);
42
+ }
43
+ }
44
+ /**
45
+ * Creates a new online meeting
46
+ * @param logger
47
+ * @param options
48
+ * @returns MS Graph online meeting response
49
+ */
50
+ async createMeeting(logger, options) {
51
+ let requestUrl = `${this.resource}/v1.0/me`;
52
+ if (options.organizerEmail) {
53
+ if (this.verbose) {
54
+ await logger.logToStderr(`Retrieving Organizer Id...`);
55
+ }
56
+ const organizerId = await aadUser.getUserIdByEmail(options.organizerEmail);
57
+ requestUrl = `${this.resource}/v1.0/users/${organizerId}`;
58
+ }
59
+ if (this.verbose) {
60
+ await logger.logToStderr(`Creating the meeting...`);
61
+ }
62
+ const requestData = {};
63
+ if (options.participantUserNames) {
64
+ const attendees = options.participantUserNames.trim().toLowerCase().split(',').map(p => ({
65
+ upn: p.trim()
66
+ }));
67
+ requestData.participants = { attendees };
68
+ }
69
+ if (options.startTime) {
70
+ requestData.startDateTime = options.startTime;
71
+ }
72
+ if (options.endTime) {
73
+ requestData.endDateTime = options.endTime;
74
+ if (!options.startTime) {
75
+ requestData.startDateTime = new Date().toISOString();
76
+ }
77
+ }
78
+ if (options.subject) {
79
+ requestData.subject = options.subject;
80
+ }
81
+ if (options.recordAutomatically !== undefined) {
82
+ requestData.recordAutomatically = true;
83
+ }
84
+ const requestOptions = {
85
+ headers: {
86
+ accept: 'application/json;odata.metadata=none',
87
+ 'content-type': 'application/json'
88
+ },
89
+ responseType: 'json',
90
+ url: `${requestUrl}/onlineMeetings`,
91
+ data: requestData
92
+ };
93
+ return request.post(requestOptions);
94
+ }
95
+ }
96
+ _TeamsMeetingAddCommand_instances = new WeakSet(), _TeamsMeetingAddCommand_initTelemetry = function _TeamsMeetingAddCommand_initTelemetry() {
97
+ this.telemetry.push((args) => {
98
+ Object.assign(this.telemetryProperties, {
99
+ startTime: typeof args.options.startTime !== 'undefined',
100
+ endTime: typeof args.options.endTime !== 'undefined',
101
+ subject: typeof args.options.subject !== 'undefined',
102
+ participantUserNames: typeof args.options.participantUserNames !== 'undefined',
103
+ organizerEmail: typeof args.options.organizerEmail !== 'undefined',
104
+ recordAutomatically: !!args.options.recordAutomatically
105
+ });
106
+ });
107
+ }, _TeamsMeetingAddCommand_initOptions = function _TeamsMeetingAddCommand_initOptions() {
108
+ this.options.unshift({
109
+ option: '-s, --startTime [startTime]'
110
+ }, {
111
+ option: '-e, --endTime [endTime]'
112
+ }, {
113
+ option: '--subject [subject]'
114
+ }, {
115
+ option: '-p, --participantUserNames [participantUserNames]'
116
+ }, {
117
+ option: '--organizerEmail [organizerEmail]'
118
+ }, {
119
+ option: '-r, --recordAutomatically'
120
+ });
121
+ }, _TeamsMeetingAddCommand_initValidators = function _TeamsMeetingAddCommand_initValidators() {
122
+ this.validators.push(async (args) => {
123
+ if (args.options.startTime && !validation.isValidISODateTime(args.options.startTime)) {
124
+ return `'${args.options.startTime}' is not a valid ISO date string for startTime.`;
125
+ }
126
+ if (args.options.endTime && !validation.isValidISODateTime(args.options.endTime)) {
127
+ return `'${args.options.endTime}' is not a valid ISO date string for endTime.`;
128
+ }
129
+ if (args.options.startTime && args.options.endTime && new Date(args.options.startTime) >= new Date(args.options.endTime)) {
130
+ return 'The startTime value must be before endTime.';
131
+ }
132
+ if (args.options.startTime && new Date() >= new Date(args.options.startTime)) {
133
+ return 'The startTime value must be in the future.';
134
+ }
135
+ if (args.options.endTime && new Date() >= new Date(args.options.endTime)) {
136
+ return 'The endTime value must be in the future.';
137
+ }
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.`;
142
+ }
143
+ }
144
+ if (args.options.organizerEmail && !validation.isValidUserPrincipalName(args.options.organizerEmail)) {
145
+ return `'${args.options.organizerEmail}' is not a valid email for organizerEmail.`;
146
+ }
147
+ return true;
148
+ });
149
+ };
150
+ export default new TeamsMeetingAddCommand();
151
+ //# sourceMappingURL=meeting-add.js.map
@@ -27,11 +27,15 @@ class TeamsUserAppRemoveCommand extends GraphCommand {
27
27
  }
28
28
  async commandAction(logger, args) {
29
29
  const removeApp = async () => {
30
+ const appId = await this.getAppId(args);
30
31
  // validation ensures that here we have either userId or userName
31
32
  const userId = (args.options.userId ?? args.options.userName);
32
33
  const endpoint = `${this.resource}/v1.0`;
34
+ if (this.verbose) {
35
+ await logger.logToStderr(`Removing app with ID ${args.options.id} for user ${args.options.userId}`);
36
+ }
33
37
  const requestOptions = {
34
- url: `${endpoint}/users/${formatting.encodeQueryParameter(userId)}/teamwork/installedApps/${args.options.id}`,
38
+ url: `${endpoint}/users/${formatting.encodeQueryParameter(userId)}/teamwork/installedApps/${appId}`,
35
39
  headers: {
36
40
  'accept': 'application/json;odata.metadata=none'
37
41
  },
@@ -54,10 +58,34 @@ class TeamsUserAppRemoveCommand extends GraphCommand {
54
58
  }
55
59
  }
56
60
  }
61
+ async getAppId(args) {
62
+ if (args.options.id) {
63
+ return args.options.id;
64
+ }
65
+ const requestOptions = {
66
+ url: `${this.resource}/v1.0/users/${args.options.userId}/teamwork/installedApps?$expand=teamsAppDefinition&$filter=teamsAppDefinition/displayName eq '${formatting.encodeQueryParameter(args.options.name)}'`,
67
+ headers: {
68
+ accept: 'application/json;odata.metadata=none'
69
+ },
70
+ responseType: 'json'
71
+ };
72
+ const response = await request.get(requestOptions);
73
+ if (response.value.length === 1) {
74
+ return response.value[0].id;
75
+ }
76
+ if (response.value.length === 0) {
77
+ throw `The specified Teams app does not exist`;
78
+ }
79
+ const resultAsKeyValuePair = formatting.convertArrayToHashTable('id', response.value);
80
+ const result = (await Cli.handleMultipleResultsFound(`Multiple Teams apps with name '${args.options.name}' found.`, resultAsKeyValuePair));
81
+ return result.id;
82
+ }
57
83
  }
58
84
  _TeamsUserAppRemoveCommand_instances = new WeakSet(), _TeamsUserAppRemoveCommand_initTelemetry = function _TeamsUserAppRemoveCommand_initTelemetry() {
59
85
  this.telemetry.push((args) => {
60
86
  Object.assign(this.telemetryProperties, {
87
+ id: typeof args.options.id !== 'undefined',
88
+ name: typeof args.options.name !== 'undefined',
61
89
  userId: typeof args.options.userId !== 'undefined',
62
90
  userName: typeof args.options.userName !== 'undefined',
63
91
  force: (!!args.options.force).toString()
@@ -65,7 +93,9 @@ _TeamsUserAppRemoveCommand_instances = new WeakSet(), _TeamsUserAppRemoveCommand
65
93
  });
66
94
  }, _TeamsUserAppRemoveCommand_initOptions = function _TeamsUserAppRemoveCommand_initOptions() {
67
95
  this.options.unshift({
68
- option: '--id <id>'
96
+ option: '--id [id]'
97
+ }, {
98
+ option: '--name [name]'
69
99
  }, {
70
100
  option: '--userId [userId]'
71
101
  }, {
@@ -84,6 +114,7 @@ _TeamsUserAppRemoveCommand_instances = new WeakSet(), _TeamsUserAppRemoveCommand
84
114
  return true;
85
115
  });
86
116
  }, _TeamsUserAppRemoveCommand_initOptionSets = function _TeamsUserAppRemoveCommand_initOptionSets() {
117
+ this.optionSets.push({ options: ['id', 'name'] });
87
118
  this.optionSets.push({ options: ['userId', 'userName'] });
88
119
  };
89
120
  export default new TeamsUserAppRemoveCommand();
@@ -27,9 +27,10 @@ export default {
27
27
  FUNSETTINGS_SET: `${prefix} funsettings set`,
28
28
  GUESTSETTINGS_LIST: `${prefix} guestsettings list`,
29
29
  GUESTSETTINGS_SET: `${prefix} guestsettings set`,
30
- MEETING_ATTENDANCEREPORT_LIST: `${prefix} meeting attendancereport list`,
30
+ MEETING_ADD: `${prefix} meeting add`,
31
31
  MEETING_GET: `${prefix} meeting get`,
32
32
  MEETING_LIST: `${prefix} meeting list`,
33
+ MEETING_ATTENDANCEREPORT_LIST: `${prefix} meeting attendancereport list`,
33
34
  MEETING_TRANSCRIPT_LIST: `${prefix} meeting transcript list`,
34
35
  MEMBERSETTINGS_LIST: `${prefix} membersettings list`,
35
36
  MEMBERSETTINGS_SET: `${prefix} membersettings set`,
package/dist/telemetry.js CHANGED
@@ -29,14 +29,6 @@ export const telemetry = {
29
29
  commandName,
30
30
  properties
31
31
  });
32
- },
33
- trackException: (exception) => {
34
- if (Cli.getInstance().getSettingWithDefaultValue(settingsNames.disableTelemetry, false)) {
35
- return;
36
- }
37
- trackTelemetry({
38
- exception
39
- });
40
32
  }
41
33
  };
42
34
  //# sourceMappingURL=telemetry.js.map
@@ -7,8 +7,11 @@ export const validation = {
7
7
  return false;
8
8
  }
9
9
  const guidRegEx = new RegExp(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
10
- // verify if the guid is a valid guid. @meid will be replaced in a later stage with the actual user id of the logged in user
11
- return guidRegEx.test(guid) || guid.toLowerCase().trim() === '@meid';
10
+ // verify if the guid is a valid guid. @meid will be replaced in a later
11
+ // stage with the actual user id of the logged in user
12
+ // we also need to make it toString in case the args is resolved as number
13
+ // or boolean
14
+ return guidRegEx.test(guid) || guid.toString().toLowerCase().trim() === '@meid';
12
15
  },
13
16
  isValidTeamsChannelId(guid) {
14
17
  const guidRegEx = new RegExp(/^19:[0-9a-zA-Z-_]+@thread\.(skype|tacv2)$/i);
@@ -14,6 +14,11 @@ m365 aad group list [options]
14
14
 
15
15
  ## Options
16
16
 
17
+ ```md definition-list
18
+ `--type [type]`
19
+ : Filter the results to only groups of a given type. Allowed values: `microsoft365`, `security`, `distribution`, `mailEnabledSecurity`. By default, all groups are listed.
20
+ ```
21
+
17
22
  <Global />
18
23
 
19
24
  ## Examples
@@ -24,6 +29,12 @@ Lists all groups defined in Azure Active Directory.
24
29
  m365 aad group list
25
30
  ```
26
31
 
32
+ List all security groups defined in Azure Active Directory.
33
+
34
+ ```sh
35
+ m365 aad group list --type security
36
+ ```
37
+
27
38
  ## Response
28
39
 
29
40
  <Tabs>
@@ -0,0 +1,179 @@
1
+ import Global from '/docs/cmd/_global.mdx';
2
+
3
+ # external connection doctor
4
+
5
+ Checks if the external connection is correctly configured for use with a specified user experience in Microsoft 365
6
+
7
+ ## Usage
8
+
9
+ ```sh
10
+ m365 external connection doctor [options]
11
+ ```
12
+
13
+ ## Options
14
+
15
+ ```md definition-list
16
+ `-i, --id <id>`
17
+ : The ID of the external connection to check.
18
+
19
+ `--ux [ux]`
20
+ : Microsoft 365 experience for which to check compatibility. Allowed values `copilot`, `search`, `all` (default)
21
+
22
+ <Global />
23
+
24
+ ## Remarks
25
+
26
+ The `external connection doctor` command runs several automated checks to verify if an external connection is correctly configured for use with a user experience in Microsoft 365.
27
+
28
+ Check|ID|UX|Type|Description
29
+ -----|--|:--:|--|------------
30
+ Required semantic labels|`copilotRequiredSemanticLabels`|Copilot|Required|Checks if the external connection schema has the required semantic labels configured: `title`, `url` and `iconUrl`
31
+ Searchable properties|Copilot|`searchableProperties`|Required|Checks if the external connection schema has at least one searchable property
32
+ Items have content ingested|`contentIngested`|Copilot|Required|Checks if external items have content ingested
33
+ Connection configured for inline results|`enabledForInlineResults`|Copilot|Required (manual)|Check if the external connection is configured for inline results
34
+ Items have activities recorded|`itemsHaveActivities`|Copilot|Recommended (manual)|Check if external items have activities recorded
35
+ Meaningful connection name and description|`meaningfulNameAndDescription`|Copilot|Required (manual)|Check if the external connection has a meaningful name and description
36
+ Semantic labels|`semanticLabels`|Search|Recommended|Checks if the external connection schema uses semantic labels
37
+ Searchable properties|`searchableProperties`|Search|Recommended|Checks if the external connection schema has at least one searchable property
38
+ Result types|`resultType`|Search|Recommended|Checks if the external connection has a result type configured
39
+ Items have content ingested|`contentIngested`|Search|Recommended|Checks if external items have content ingested
40
+ Items have activities recorded|`itemsHaveActivities`|Search|Recommended|Check if external items have activities recorded
41
+ urlToItemResolver configured|`urlToItemResolver`|All|Recommended|Checks if the external connection has at least one urlToItemResolver configured
42
+
43
+ Required checks must pass for the external connection to be compatible with the specified user experience. Recommended checks are optional, but recommended for optimal user experience.
44
+
45
+ Some checks must be done manually, because there are no APIs available to verify the configuration automatically.
46
+
47
+ When you check the compatibility with all UXs, and there are multiple checks with the same ID, the command will use the first matching check, following the order listed above.
48
+
49
+ ## Examples
50
+
51
+ Checks if the external connection with the specified ID is correctly configured for use with Copilot for Microsoft 365.
52
+
53
+ ```sh
54
+ m365 external connection doctor --id contosoproducts --ux copilot
55
+ ```
56
+
57
+ ## Response
58
+
59
+ <Tabs>
60
+ <TabItem value="JSON">
61
+
62
+ ```json
63
+ [
64
+ {
65
+ "id": "loadExternalConnection",
66
+ "text": "Load connection",
67
+ "type": "required",
68
+ "status": "passed"
69
+ },
70
+ {
71
+ "id": "loadSchema",
72
+ "text": "Load schema",
73
+ "type": "required",
74
+ "status": "passed"
75
+ },
76
+ {
77
+ "id": "copilotRequiredSemanticLabels",
78
+ "text": "Required semantic labels",
79
+ "type": "required",
80
+ "errorMessage": "Missing label iconUrl",
81
+ "status": "failed"
82
+ },
83
+ {
84
+ "id": "searchableProperties",
85
+ "text": "Searchable properties",
86
+ "type": "required",
87
+ "status": "passed"
88
+ },
89
+ {
90
+ "id": "contentIngested",
91
+ "text": "Items have content ingested",
92
+ "type": "required",
93
+ "status": "passed"
94
+ },
95
+ {
96
+ "id": "enabledForInlineResults",
97
+ "text": "Connection configured for inline results",
98
+ "type": "required",
99
+ "status": "manual"
100
+ },
101
+ {
102
+ "id": "itemsHaveActivities",
103
+ "text": "Items have activities recorded",
104
+ "type": "recommended",
105
+ "status": "manual"
106
+ },
107
+ {
108
+ "id": "meaningfulNameAndDescription",
109
+ "text": "Meaningful connection name and description",
110
+ "type": "required",
111
+ "status": "manual"
112
+ },
113
+ {
114
+ "id": "urlToItemResolver",
115
+ "text": "urlToItemResolver configured",
116
+ "type": "recommended",
117
+ "status": "passed"
118
+ }
119
+ ]
120
+ ```
121
+
122
+ </TabItem>
123
+ <TabItem value="Text">
124
+
125
+ ```text
126
+ ✔ Load connection
127
+ ✔ Load schema
128
+ ✖ Required semantic labels: Missing label iconUrl
129
+ ✔ Searchable properties
130
+ ✔ Items have content ingested
131
+ ℹ Connection configured for inline results (manual)
132
+ ℹ Items have activities recorded (manual)
133
+ ℹ Meaningful connection name and description (manual)
134
+ ✔ urlToItemResolver configured
135
+ ```
136
+
137
+ </TabItem>
138
+ <TabItem value="CSV">
139
+
140
+ ```csv
141
+ id,text,type,status,errorMessage
142
+ loadExternalConnection,Load connection,required,passed,
143
+ loadSchema,Load schema,required,passed,
144
+ copilotRequiredSemanticLabels,Required semantic labels,required,failed,Missing label iconUrl
145
+ searchableProperties,Searchable properties,required,passed,
146
+ contentIngested,Items have content ingested,required,passed,
147
+ enabledForInlineResults,Connection configured for inline results,required,manual,
148
+ itemsHaveActivities,Items have activities recorded,recommended,manual,
149
+ meaningfulNameAndDescription,Meaningful connection name and description,required,manual,
150
+ urlToItemResolver,urlToItemResolver configured,recommended,passed,
151
+ ```
152
+
153
+ </TabItem>
154
+ <TabItem value="Markdown">
155
+
156
+ ```md
157
+ # external connection doctor --id "msgraphdocs" --ux "copilot"
158
+
159
+ Date: 11/23/2023
160
+
161
+ Check|Type|Status|Error message
162
+ :----|:--:|:----:|:------------
163
+ Load connection|required|passed|
164
+ Load schema|required|passed|
165
+ Required semantic labels|required|failed|Missing label iconUrl
166
+ Searchable properties|required|passed|
167
+ Items have content ingested|required|passed|
168
+ Connection configured for inline results|required|manual|
169
+ Items have activities recorded|recommended|manual|
170
+ Meaningful connection name and description|required|manual|
171
+ urlToItemResolver configured|recommended|passed|
172
+ ```
173
+
174
+ </TabItem>
175
+ </Tabs>
176
+
177
+ ## More information
178
+
179
+ - Microsoft Graph connector experiences: [https://learn.microsoft.com/graph/connecting-external-content-experiences](https://learn.microsoft.com/graph/connecting-external-content-experiences)