@pnp/cli-microsoft365 5.3.0-beta.f028e14 → 5.3.0

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 (111) hide show
  1. package/.eslintrc.js +1 -0
  2. package/dist/Auth.js +5 -0
  3. package/dist/m365/aad/commands/app/app-add.js +91 -35
  4. package/dist/m365/aad/commands/app/app-role-list.js +1 -1
  5. package/dist/m365/aad/commands/app/app-set.js +91 -0
  6. package/dist/m365/aad/commands/approleassignment/approleassignment-list.js +55 -22
  7. package/dist/m365/aad/commands/group/group-list.js +1 -1
  8. package/dist/m365/aad/commands/groupsetting/groupsetting-list.js +1 -1
  9. package/dist/m365/aad/commands/groupsettingtemplate/groupsettingtemplate-get.js +1 -1
  10. package/dist/m365/aad/commands/groupsettingtemplate/groupsettingtemplate-list.js +1 -1
  11. package/dist/m365/aad/commands/o365group/o365group-conversation-list.js +1 -1
  12. package/dist/m365/aad/commands/o365group/o365group-conversation-post-list.js +1 -1
  13. package/dist/m365/aad/commands/o365group/o365group-list.js +1 -1
  14. package/dist/m365/aad/commands/o365group/o365group-recyclebinitem-clear.js +3 -3
  15. package/dist/m365/aad/commands/o365group/o365group-recyclebinitem-list.js +1 -1
  16. package/dist/m365/aad/commands/o365group/o365group-user-list.js +2 -2
  17. package/dist/m365/aad/commands/o365group/o365group-user-set.js +2 -2
  18. package/dist/m365/aad/commands/user/user-list.js +1 -1
  19. package/dist/m365/aad/commands/user/user-signin-list.js +1 -1
  20. package/dist/m365/aad/commands.js +1 -1
  21. package/dist/m365/app/commands/app-open.js +64 -0
  22. package/dist/m365/app/commands.js +1 -0
  23. package/dist/m365/base/PowerBICommand.js +10 -0
  24. package/dist/m365/file/commands/file-list.js +1 -1
  25. package/dist/m365/outlook/commands/message/message-list.js +1 -1
  26. package/dist/m365/outlook/commands/room/room-list.js +1 -1
  27. package/dist/m365/outlook/commands/roomlist/roomlist-list.js +1 -1
  28. package/dist/m365/planner/commands/bucket/bucket-add.js +8 -16
  29. package/dist/m365/planner/commands/bucket/bucket-get.js +186 -0
  30. package/dist/m365/planner/commands/bucket/bucket-list.js +10 -19
  31. package/dist/m365/planner/commands/bucket/bucket-remove.js +8 -20
  32. package/dist/m365/planner/commands/bucket/bucket-set.js +9 -21
  33. package/dist/m365/planner/commands/plan/plan-add.js +6 -1
  34. package/dist/m365/planner/commands/plan/plan-details-get.js +12 -15
  35. package/dist/m365/planner/commands/plan/plan-get.js +13 -18
  36. package/dist/m365/planner/commands/plan/plan-list.js +10 -13
  37. package/dist/m365/planner/commands/task/task-add.js +8 -16
  38. package/dist/m365/planner/commands/task/task-details-get.js +6 -0
  39. package/dist/m365/planner/commands/task/task-get.js +138 -7
  40. package/dist/m365/planner/commands/task/task-list.js +15 -24
  41. package/dist/m365/planner/commands/task/task-reference-add.js +75 -0
  42. package/dist/m365/planner/commands/task/task-reference-list.js +45 -0
  43. package/dist/m365/planner/commands/task/task-set.js +9 -18
  44. package/dist/m365/planner/commands.js +4 -1
  45. package/dist/m365/pp/commands/gateway/gateway-list.js +36 -0
  46. package/dist/m365/pp/commands/managementapp/managementapp-list.js +1 -1
  47. package/dist/m365/pp/commands.js +1 -0
  48. package/dist/m365/search/commands/externalconnection/externalconnection-list.js +26 -0
  49. package/dist/m365/search/commands.js +2 -1
  50. package/dist/m365/spo/commands/eventreceiver/eventreceiver-get.js +119 -0
  51. package/dist/m365/spo/commands/field/field-list.js +84 -0
  52. package/dist/m365/spo/commands/list/list-roleinheritance-break.js +84 -0
  53. package/dist/m365/spo/commands/list/list-roleinheritance-reset.js +76 -0
  54. package/dist/m365/spo/commands/list/list-view-add.js +113 -0
  55. package/dist/m365/spo/commands/listitem/listitem-roleinheritance-break.js +83 -0
  56. package/dist/m365/spo/commands/listitem/listitem-roleinheritance-reset.js +79 -0
  57. package/dist/m365/spo/commands/roledefinition/roledefinition-list.js +49 -0
  58. package/dist/m365/spo/commands.js +8 -0
  59. package/dist/m365/teams/commands/app/app-list.js +1 -1
  60. package/dist/m365/teams/commands/channel/channel-list.js +1 -1
  61. package/dist/m365/teams/commands/channel/channel-member-add.js +4 -1
  62. package/dist/m365/teams/commands/channel/channel-member-list.js +1 -1
  63. package/dist/m365/teams/commands/channel/channel-member-remove.js +3 -0
  64. package/dist/m365/teams/commands/channel/channel-member-set.js +3 -0
  65. package/dist/m365/teams/commands/chat/chat-get.js +8 -8
  66. package/dist/m365/teams/commands/chat/chat-list.js +1 -1
  67. package/dist/m365/teams/commands/chat/chat-member-list.js +1 -1
  68. package/dist/m365/teams/commands/chat/chat-message-list.js +1 -1
  69. package/dist/m365/teams/commands/chat/chat-message-send.js +6 -6
  70. package/dist/m365/teams/commands/chat/chatUtil.js +4 -4
  71. package/dist/m365/teams/commands/message/message-list.js +1 -1
  72. package/dist/m365/teams/commands/message/message-reply-list.js +1 -1
  73. package/dist/m365/teams/commands/tab/tab-list.js +1 -1
  74. package/dist/m365/teams/commands/team/team-list.js +1 -1
  75. package/dist/m365/teams/commands/user/user-app-list.js +1 -1
  76. package/dist/m365/teams/commands/user/user-list.js +2 -2
  77. package/dist/m365/tenant/commands/security/security-alerts-list.js +71 -0
  78. package/dist/m365/tenant/commands/serviceannouncement/serviceannouncement-healthissue-list.js +1 -1
  79. package/dist/m365/tenant/commands/serviceannouncement/serviceannouncement-message-list.js +1 -1
  80. package/dist/m365/tenant/commands.js +1 -0
  81. package/dist/m365/todo/commands/list/list-list.js +1 -1
  82. package/dist/m365/todo/commands/task/task-list.js +1 -1
  83. package/dist/utils/accessToken.js +18 -0
  84. package/dist/utils/formatting.js +11 -2
  85. package/dist/utils/odata.js +2 -2
  86. package/dist/utils/planner.js +65 -0
  87. package/docs/docs/cmd/aad/app/app-add.md +15 -0
  88. package/docs/docs/cmd/aad/app/app-set.md +17 -0
  89. package/docs/docs/cmd/aad/approleassignment/approleassignment-remove.md +1 -1
  90. package/docs/docs/cmd/app/app-open.md +45 -0
  91. package/docs/docs/cmd/planner/bucket/bucket-get.md +57 -0
  92. package/docs/docs/cmd/planner/task/task-get.md +30 -3
  93. package/docs/docs/cmd/planner/task/task-reference-add.md +45 -0
  94. package/docs/docs/cmd/planner/task/task-reference-list.md +24 -0
  95. package/docs/docs/cmd/pp/gateway/gateway-list.md +21 -0
  96. package/docs/docs/cmd/search/externalconnection/externalconnection-list.md +21 -0
  97. package/docs/docs/cmd/spo/eventreceiver/eventreceiver-get.md +70 -0
  98. package/docs/docs/cmd/spo/field/field-list.md +51 -0
  99. package/docs/docs/cmd/spo/list/list-roleinheritance-break.md +55 -0
  100. package/docs/docs/cmd/spo/list/list-roleinheritance-reset.md +36 -0
  101. package/docs/docs/cmd/spo/list/list-view-add.md +67 -0
  102. package/docs/docs/cmd/spo/listitem/listitem-roleinheritance-break.md +58 -0
  103. package/docs/docs/cmd/spo/listitem/listitem-roleinheritance-reset.md +39 -0
  104. package/docs/docs/cmd/spo/roledefinition/roledefinition-list.md +24 -0
  105. package/docs/docs/cmd/spo/userprofile/userprofile-get.md +1 -1
  106. package/docs/docs/cmd/teams/channel/channel-member-list.md +4 -4
  107. package/docs/docs/cmd/teams/channel/channel-member-remove.md +2 -2
  108. package/docs/docs/cmd/teams/channel/channel-member-set.md +2 -2
  109. package/docs/docs/cmd/tenant/security/security-alerts-list.md +30 -0
  110. package/npm-shrinkwrap.json +1515 -1282
  111. package/package.json +26 -25
package/.eslintrc.js CHANGED
@@ -29,6 +29,7 @@ const dictionary = [
29
29
  'home',
30
30
  'hub',
31
31
  'in',
32
+ 'inheritance',
32
33
  'init',
33
34
  'install',
34
35
  'installed',
package/dist/Auth.js CHANGED
@@ -540,6 +540,11 @@ class Auth {
540
540
  // we need to use https://management.azure.com/ instead
541
541
  resource = 'https://management.azure.com/';
542
542
  }
543
+ if (resource === 'https://api.powerbi.com') {
544
+ // api.powerbi.com is not a valid resource
545
+ // we need to use https://analysis.windows.net/powerbi/api instead
546
+ resource = 'https://analysis.windows.net/powerbi/api';
547
+ }
543
548
  return resource;
544
549
  }
545
550
  getServiceConnectionInfo() {
@@ -1,4 +1,13 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  const fs = require("fs");
4
13
  const uuid_1 = require("uuid");
@@ -31,6 +40,9 @@ class AadAppAddCommand extends GraphCommand_1.default {
31
40
  telemetryProps.scopeName = typeof args.options.scopeName !== 'undefined';
32
41
  telemetryProps.uri = typeof args.options.uri !== 'undefined';
33
42
  telemetryProps.withSecret = args.options.withSecret;
43
+ telemetryProps.certificateFile = typeof args.options.certificateFile !== 'undefined';
44
+ telemetryProps.certificateBase64Encoded = typeof args.options.certificateBase64Encoded !== 'undefined';
45
+ telemetryProps.certificateDisplayName = typeof args.options.certificateDisplayName !== 'undefined';
34
46
  return telemetryProps;
35
47
  }
36
48
  commandAction(logger, args, cb) {
@@ -66,43 +78,55 @@ class AadAppAddCommand extends GraphCommand_1.default {
66
78
  }, (rawRes) => this.handleRejectedODataJsonPromise(rawRes, logger, cb));
67
79
  }
68
80
  createAppRegistration(args, apis, logger) {
69
- const applicationInfo = {
70
- displayName: args.options.name,
71
- signInAudience: args.options.multitenant ? 'AzureADMultipleOrgs' : 'AzureADMyOrg'
72
- };
73
- if (!applicationInfo.displayName && this.manifest) {
74
- applicationInfo.displayName = this.manifest.name;
75
- }
76
- this.appName = applicationInfo.displayName;
77
- if (apis.length > 0) {
78
- applicationInfo.requiredResourceAccess = apis;
79
- }
80
- if (args.options.redirectUris) {
81
- applicationInfo[args.options.platform] = {
82
- redirectUris: args.options.redirectUris.split(',').map(u => u.trim())
81
+ return __awaiter(this, void 0, void 0, function* () {
82
+ const applicationInfo = {
83
+ displayName: args.options.name,
84
+ signInAudience: args.options.multitenant ? 'AzureADMultipleOrgs' : 'AzureADMyOrg'
83
85
  };
84
- }
85
- if (args.options.implicitFlow) {
86
- if (!applicationInfo.web) {
87
- applicationInfo.web = {};
86
+ if (!applicationInfo.displayName && this.manifest) {
87
+ applicationInfo.displayName = this.manifest.name;
88
+ }
89
+ this.appName = applicationInfo.displayName;
90
+ if (apis.length > 0) {
91
+ applicationInfo.requiredResourceAccess = apis;
92
+ }
93
+ if (args.options.redirectUris) {
94
+ applicationInfo[args.options.platform] = {
95
+ redirectUris: args.options.redirectUris.split(',').map(u => u.trim())
96
+ };
97
+ }
98
+ if (args.options.implicitFlow) {
99
+ if (!applicationInfo.web) {
100
+ applicationInfo.web = {};
101
+ }
102
+ applicationInfo.web.implicitGrantSettings = {
103
+ enableAccessTokenIssuance: true,
104
+ enableIdTokenIssuance: true
105
+ };
88
106
  }
89
- applicationInfo.web.implicitGrantSettings = {
90
- enableAccessTokenIssuance: true,
91
- enableIdTokenIssuance: true
107
+ if (args.options.certificateFile || args.options.certificateBase64Encoded) {
108
+ const certificateBase64Encoded = this.getCertificateBase64Encoded(args, logger);
109
+ const newKeyCredential = {
110
+ type: "AsymmetricX509Cert",
111
+ usage: "Verify",
112
+ displayName: args.options.certificateDisplayName,
113
+ key: certificateBase64Encoded
114
+ };
115
+ applicationInfo.keyCredentials = [newKeyCredential];
116
+ }
117
+ if (this.verbose) {
118
+ logger.logToStderr(`Creating Azure AD app registration...`);
119
+ }
120
+ const createApplicationRequestOptions = {
121
+ url: `${this.resource}/v1.0/myorganization/applications`,
122
+ headers: {
123
+ accept: 'application/json;odata.metadata=none'
124
+ },
125
+ responseType: 'json',
126
+ data: applicationInfo
92
127
  };
93
- }
94
- if (this.verbose) {
95
- logger.logToStderr(`Creating Azure AD app registration...`);
96
- }
97
- const createApplicationRequestOptions = {
98
- url: `${this.resource}/v1.0/myorganization/applications`,
99
- headers: {
100
- accept: 'application/json;odata.metadata=none'
101
- },
102
- responseType: 'json',
103
- data: applicationInfo
104
- };
105
- return request_1.default.post(createApplicationRequestOptions);
128
+ return request_1.default.post(createApplicationRequestOptions);
129
+ });
106
130
  }
107
131
  updateAppFromManifest(args, appInfo) {
108
132
  if (!args.options.manifest) {
@@ -325,7 +349,7 @@ class AadAppAddCommand extends GraphCommand_1.default {
325
349
  logger.logToStderr('Resolving requested APIs...');
326
350
  }
327
351
  return utils_1.odata
328
- .getAllItems(`${this.resource}/v1.0/myorganization/servicePrincipals?$select=servicePrincipalNames,appId,oauth2PermissionScopes,appRoles`, logger)
352
+ .getAllItems(`${this.resource}/v1.0/myorganization/servicePrincipals?$select=servicePrincipalNames,appId,oauth2PermissionScopes,appRoles`)
329
353
  .then(servicePrincipals => {
330
354
  try {
331
355
  const resolvedApis = this.getRequiredResourceAccessForApis(servicePrincipals, args.options.apisDelegated, 'Scope', logger);
@@ -437,6 +461,20 @@ class AadAppAddCommand extends GraphCommand_1.default {
437
461
  value: password.secretText
438
462
  }));
439
463
  }
464
+ getCertificateBase64Encoded(args, logger) {
465
+ if (args.options.certificateBase64Encoded) {
466
+ return args.options.certificateBase64Encoded;
467
+ }
468
+ if (this.debug) {
469
+ logger.logToStderr(`Reading existing ${args.options.certificateFile}...`);
470
+ }
471
+ try {
472
+ return fs.readFileSync(args.options.certificateFile, { encoding: 'base64' });
473
+ }
474
+ catch (e) {
475
+ throw new Error(`Error reading certificate file: ${e}. Please add the certificate using base64 option '--certificateBase64Encoded'.`);
476
+ }
477
+ }
440
478
  saveAppInfo(args, appInfo, logger) {
441
479
  if (!args.options.save) {
442
480
  return Promise.resolve(appInfo);
@@ -519,6 +557,15 @@ class AadAppAddCommand extends GraphCommand_1.default {
519
557
  {
520
558
  option: '--scopeAdminConsentDescription [scopeAdminConsentDescription]'
521
559
  },
560
+ {
561
+ option: '--certificateFile [certificateFile]'
562
+ },
563
+ {
564
+ option: '--certificateBase64Encoded [certificateBase64Encoded]'
565
+ },
566
+ {
567
+ option: '--certificateDisplayName [certificateDisplayName]'
568
+ },
522
569
  {
523
570
  option: '--manifest [manifest]'
524
571
  },
@@ -540,6 +587,15 @@ class AadAppAddCommand extends GraphCommand_1.default {
540
587
  if (args.options.redirectUris && !args.options.platform) {
541
588
  return `When you specify redirectUris you also need to specify platform`;
542
589
  }
590
+ if (args.options.certificateFile && args.options.certificateBase64Encoded) {
591
+ return 'Specify either certificateFile or certificateBase64Encoded but not both';
592
+ }
593
+ if (args.options.certificateDisplayName && !args.options.certificateFile && !args.options.certificateBase64Encoded) {
594
+ return 'When you specify certificateDisplayName you also need to specify certificateFile or certificateBase64Encoded';
595
+ }
596
+ if (args.options.certificateFile && !fs.existsSync(args.options.certificateFile)) {
597
+ return 'Certificate file not found';
598
+ }
543
599
  if (args.options.scopeName) {
544
600
  if (!args.options.uri) {
545
601
  return `When you specify scopeName you also need to specify uri`;
@@ -24,7 +24,7 @@ class AadAppRoleListCommand extends GraphCommand_1.default {
24
24
  commandAction(logger, args, cb) {
25
25
  this
26
26
  .getAppObjectId(args, logger)
27
- .then(objectId => utils_1.odata.getAllItems(`${this.resource}/v1.0/myorganization/applications/${objectId}/appRoles`, logger))
27
+ .then(objectId => utils_1.odata.getAllItems(`${this.resource}/v1.0/myorganization/applications/${objectId}/appRoles`))
28
28
  .then(appRoles => {
29
29
  logger.log(appRoles);
30
30
  cb();
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const fs = require("fs");
3
4
  const request_1 = require("../../../../request");
4
5
  const GraphCommand_1 = require("../../../base/GraphCommand");
5
6
  const commands_1 = require("../../commands");
@@ -19,6 +20,9 @@ class AadAppSetCommand extends GraphCommand_1.default {
19
20
  telemetryProps.redirectUris = typeof args.options.redirectUris !== 'undefined';
20
21
  telemetryProps.redirectUrisToRemove = typeof args.options.redirectUrisToRemove !== 'undefined';
21
22
  telemetryProps.uri = typeof args.options.uri !== 'undefined';
23
+ telemetryProps.certificateFile = typeof args.options.certificateFile !== 'undefined';
24
+ telemetryProps.certificateBase64Encoded = typeof args.options.certificateBase64Encoded !== 'undefined';
25
+ telemetryProps.certificateDisplayName = typeof args.options.certificateDisplayName !== 'undefined';
22
26
  return telemetryProps;
23
27
  }
24
28
  commandAction(logger, args, cb) {
@@ -26,6 +30,7 @@ class AadAppSetCommand extends GraphCommand_1.default {
26
30
  .getAppObjectId(args, logger)
27
31
  .then(objectId => this.configureUri(args, objectId, logger))
28
32
  .then(objectId => this.configureRedirectUris(args, objectId, logger))
33
+ .then(objectId => this.configureCertificate(args, objectId, logger))
29
34
  .then(_ => cb(), (rawRes) => this.handleRejectedODataJsonPromise(rawRes, logger, cb));
30
35
  }
31
36
  getAppObjectId(args, logger) {
@@ -156,6 +161,80 @@ class AadAppSetCommand extends GraphCommand_1.default {
156
161
  })
157
162
  .then(_ => Promise.resolve(objectId));
158
163
  }
164
+ configureCertificate(args, objectId, logger) {
165
+ if (!args.options.certificateFile && !args.options.certificateBase64Encoded) {
166
+ return Promise.resolve();
167
+ }
168
+ if (this.verbose) {
169
+ logger.logToStderr(`Setting certificate for Azure AD app...`);
170
+ }
171
+ const certificateBase64Encoded = this.getCertificateBase64Encoded(args, logger);
172
+ return this
173
+ .getCurrentKeyCredentialsList(args, objectId, certificateBase64Encoded, logger)
174
+ .then(currentKeyCredentials => {
175
+ if (this.verbose) {
176
+ logger.logToStderr(`Adding new keyCredential to list`);
177
+ }
178
+ // The KeyCredential graph type defines the 'key' property as 'NullableOption<number>'
179
+ // while it is a base64 encoded string. This is why a cast to any is used here.
180
+ const keyCredentials = currentKeyCredentials.filter(existingCredential => existingCredential.key !== certificateBase64Encoded);
181
+ const newKeyCredential = {
182
+ type: "AsymmetricX509Cert",
183
+ usage: "Verify",
184
+ displayName: args.options.certificateDisplayName,
185
+ key: certificateBase64Encoded
186
+ };
187
+ keyCredentials.push(newKeyCredential);
188
+ return Promise.resolve(keyCredentials);
189
+ })
190
+ .then(keyCredentials => this.updateKeyCredentials(objectId, keyCredentials, logger));
191
+ }
192
+ getCertificateBase64Encoded(args, logger) {
193
+ if (args.options.certificateBase64Encoded) {
194
+ return args.options.certificateBase64Encoded;
195
+ }
196
+ if (this.debug) {
197
+ logger.logToStderr(`Reading existing ${args.options.certificateFile}...`);
198
+ }
199
+ try {
200
+ return fs.readFileSync(args.options.certificateFile, { encoding: 'base64' });
201
+ }
202
+ catch (e) {
203
+ throw new Error(`Error reading certificate file: ${e}. Please add the certificate using base64 option '--certificateBase64Encoded'.`);
204
+ }
205
+ }
206
+ // We first retrieve existing certificates because we need to specify the full list of certificates when updating the app.
207
+ getCurrentKeyCredentialsList(args, objectId, certificateBase64Encoded, logger) {
208
+ if (this.verbose) {
209
+ logger.logToStderr(`Retrieving current keyCredentials list for app`);
210
+ }
211
+ const getAppRequestOptions = {
212
+ url: `${this.resource}/v1.0/myorganization/applications/${objectId}?$select=keyCredentials`,
213
+ headers: {
214
+ 'content-type': 'application/json;odata.metadata=none'
215
+ },
216
+ responseType: 'json'
217
+ };
218
+ return request_1.default.get(getAppRequestOptions).then((application) => {
219
+ return Promise.resolve(application.keyCredentials || []);
220
+ });
221
+ }
222
+ updateKeyCredentials(objectId, keyCredentials, logger) {
223
+ if (this.verbose) {
224
+ logger.logToStderr(`Updating keyCredentials in AAD app`);
225
+ }
226
+ const requestOptions = {
227
+ url: `${this.resource}/v1.0/myorganization/applications/${objectId}`,
228
+ headers: {
229
+ 'content-type': 'application/json;odata.metadata=none'
230
+ },
231
+ responseType: 'json',
232
+ data: {
233
+ keyCredentials: keyCredentials
234
+ }
235
+ };
236
+ return request_1.default.patch(requestOptions);
237
+ }
159
238
  options() {
160
239
  const options = [
161
240
  { option: '--appId [appId]' },
@@ -163,6 +242,9 @@ class AadAppSetCommand extends GraphCommand_1.default {
163
242
  { option: '-n, --name [name]' },
164
243
  { option: '-u, --uri [uri]' },
165
244
  { option: '-r, --redirectUris [redirectUris]' },
245
+ { option: '--certificateFile [certificateFile]' },
246
+ { option: '--certificateBase64Encoded [certificateBase64Encoded]' },
247
+ { option: '--certificateDisplayName [certificateDisplayName]' },
166
248
  {
167
249
  option: '--platform [platform]',
168
250
  autocomplete: AadAppSetCommand.aadApplicationPlatform
@@ -183,6 +265,15 @@ class AadAppSetCommand extends GraphCommand_1.default {
183
265
  (args.options.objectId && args.options.name)) {
184
266
  return 'Specify either appId, objectId or name but not both';
185
267
  }
268
+ if (args.options.certificateFile && args.options.certificateBase64Encoded) {
269
+ return 'Specify either certificateFile or certificateBase64Encoded but not both';
270
+ }
271
+ if (args.options.certificateDisplayName && !args.options.certificateFile && !args.options.certificateBase64Encoded) {
272
+ return 'When you specify certificateDisplayName you also need to specify certificateFile or certificateBase64Encoded';
273
+ }
274
+ if (args.options.certificateFile && !fs.existsSync(args.options.certificateFile)) {
275
+ return 'Certificate file not found';
276
+ }
186
277
  if (args.options.redirectUris && !args.options.platform) {
187
278
  return `When you specify redirectUris you also need to specify platform`;
188
279
  }
@@ -22,29 +22,14 @@ class AadAppRoleAssignmentListCommand extends GraphCommand_1.default {
22
22
  return ['resourceDisplayName', 'roleName'];
23
23
  }
24
24
  commandAction(logger, args, cb) {
25
- let sp;
26
- // get the service principal associated with the appId
27
- let spMatchQuery = '';
28
- if (args.options.appId) {
29
- spMatchQuery = `appId eq '${encodeURIComponent(args.options.appId)}'`;
30
- }
31
- else if (args.options.objectId) {
32
- spMatchQuery = `id eq '${encodeURIComponent(args.options.objectId)}'`;
33
- }
34
- else {
35
- spMatchQuery = `displayName eq '${encodeURIComponent(args.options.displayName)}'`;
36
- }
37
- this
38
- .getServicePrincipalForApp(spMatchQuery)
39
- .then((resp) => {
40
- if (!resp.value.length) {
41
- return Promise.reject('app registration not found');
42
- }
43
- sp = resp.value[0];
25
+ let spAppRoleAssignments;
26
+ this.getAppRoleAssignments(args.options)
27
+ .then((appRoleAssignments) => {
28
+ spAppRoleAssignments = appRoleAssignments;
44
29
  // the role assignment has an appRoleId but no name. To get the name,
45
30
  // we need to get all the roles from the resource. the resource is
46
31
  // a service principal. Multiple roles may have same resource id.
47
- const resourceIds = sp.appRoleAssignments.map((item) => item.resourceId);
32
+ const resourceIds = appRoleAssignments.map((item) => item.resourceId);
48
33
  const tasks = [];
49
34
  for (let i = 0; i < resourceIds.length; i++) {
50
35
  tasks.push(this.getServicePrincipal(resourceIds[i]));
@@ -55,7 +40,7 @@ class AadAppRoleAssignmentListCommand extends GraphCommand_1.default {
55
40
  // loop through all appRoleAssignments for the servicePrincipal
56
41
  // and lookup the appRole.Id in the resources[resourceId].appRoles array...
57
42
  const results = [];
58
- sp.appRoleAssignments.map((appRoleAssignment) => {
43
+ spAppRoleAssignments.map((appRoleAssignment) => {
59
44
  const resource = resources.find((r) => r.id === appRoleAssignment.resourceId);
60
45
  if (resource) {
61
46
  const appRole = resource.appRoles.find((r) => r.id === appRoleAssignment.appRoleId);
@@ -65,7 +50,9 @@ class AadAppRoleAssignmentListCommand extends GraphCommand_1.default {
65
50
  resourceDisplayName: appRoleAssignment.resourceDisplayName,
66
51
  resourceId: appRoleAssignment.resourceId,
67
52
  roleId: appRole.id,
68
- roleName: appRole.value
53
+ roleName: appRole.value,
54
+ created: appRoleAssignment.createdDateTime,
55
+ deleted: appRoleAssignment.deletedDateTime
69
56
  });
70
57
  }
71
58
  }
@@ -74,6 +61,52 @@ class AadAppRoleAssignmentListCommand extends GraphCommand_1.default {
74
61
  cb();
75
62
  }, (err) => this.handleRejectedODataJsonPromise(err, logger, cb));
76
63
  }
64
+ getAppRoleAssignments(argOptions) {
65
+ return new Promise((resolve, reject) => {
66
+ if (argOptions.objectId) {
67
+ this.getSPAppRoleAssignments(argOptions.objectId)
68
+ .then((spAppRoleAssignments) => {
69
+ if (!spAppRoleAssignments.value.length) {
70
+ reject('no app role assignments found');
71
+ }
72
+ resolve(spAppRoleAssignments.value);
73
+ })
74
+ .catch((err) => {
75
+ reject(err);
76
+ });
77
+ }
78
+ else {
79
+ // Use existing way to get service principal object
80
+ let spMatchQuery = '';
81
+ if (argOptions.appId) {
82
+ spMatchQuery = `appId eq '${encodeURIComponent(argOptions.appId)}'`;
83
+ }
84
+ else {
85
+ spMatchQuery = `displayName eq '${encodeURIComponent(argOptions.displayName)}'`;
86
+ }
87
+ this.getServicePrincipalForApp(spMatchQuery)
88
+ .then((resp) => {
89
+ if (!resp.value.length) {
90
+ reject('app registration not found');
91
+ }
92
+ resolve(resp.value[0].appRoleAssignments);
93
+ })
94
+ .catch((err) => {
95
+ reject(err);
96
+ });
97
+ }
98
+ });
99
+ }
100
+ getSPAppRoleAssignments(spId) {
101
+ const spRequestOptions = {
102
+ url: `${this.resource}/v1.0/servicePrincipals/${spId}/appRoleAssignments`,
103
+ headers: {
104
+ accept: 'application/json'
105
+ },
106
+ responseType: 'json'
107
+ };
108
+ return request_1.default.get(spRequestOptions);
109
+ }
77
110
  getServicePrincipalForApp(filterParam) {
78
111
  const spRequestOptions = {
79
112
  url: `${this.resource}/v1.0/servicePrincipals?$expand=appRoleAssignments&$filter=${filterParam}`,
@@ -21,7 +21,7 @@ class AadGroupListCommand extends GraphCommand_1.default {
21
21
  commandAction(logger, args, cb) {
22
22
  const endpoint = args.options.deleted ? 'directory/deletedItems/microsoft.graph.group' : 'groups';
23
23
  utils_1.odata
24
- .getAllItems(`${this.resource}/v1.0/${endpoint}`, logger)
24
+ .getAllItems(`${this.resource}/v1.0/${endpoint}`)
25
25
  .then((groups) => {
26
26
  if (args.options.output === 'text') {
27
27
  groups.forEach((group) => {
@@ -15,7 +15,7 @@ class AadGroupSettingListCommand extends GraphCommand_1.default {
15
15
  }
16
16
  commandAction(logger, args, cb) {
17
17
  utils_1.odata
18
- .getAllItems(`${this.resource}/v1.0/groupSettings`, logger)
18
+ .getAllItems(`${this.resource}/v1.0/groupSettings`)
19
19
  .then((groupSettings) => {
20
20
  logger.log(groupSettings);
21
21
  cb();
@@ -19,7 +19,7 @@ class AadGroupSettingTemplateGetCommand extends GraphCommand_1.default {
19
19
  }
20
20
  commandAction(logger, args, cb) {
21
21
  utils_1.odata
22
- .getAllItems(`${this.resource}/v1.0/groupSettingTemplates`, logger)
22
+ .getAllItems(`${this.resource}/v1.0/groupSettingTemplates`)
23
23
  .then((templates) => {
24
24
  const groupSettingTemplate = templates.filter(t => args.options.id ? t.id === args.options.id : t.displayName === args.options.displayName);
25
25
  if (groupSettingTemplate && groupSettingTemplate.length > 0) {
@@ -15,7 +15,7 @@ class AadGroupSettingTemplateListCommand extends GraphCommand_1.default {
15
15
  }
16
16
  commandAction(logger, args, cb) {
17
17
  utils_1.odata
18
- .getAllItems(`${this.resource}/v1.0/groupSettingTemplates`, logger)
18
+ .getAllItems(`${this.resource}/v1.0/groupSettingTemplates`)
19
19
  .then((templates) => {
20
20
  logger.log(templates);
21
21
  cb();
@@ -15,7 +15,7 @@ class AadO365GroupConversationListCommand extends GraphCommand_1.default {
15
15
  }
16
16
  commandAction(logger, args, cb) {
17
17
  utils_1.odata
18
- .getAllItems(`${this.resource}/v1.0/groups/${args.options.groupId}/conversations`, logger)
18
+ .getAllItems(`${this.resource}/v1.0/groups/${args.options.groupId}/conversations`)
19
19
  .then((conversations) => {
20
20
  logger.log(conversations);
21
21
  cb();
@@ -24,7 +24,7 @@ class AadO365GroupConversationPostListCommand extends GraphCommand_1.default {
24
24
  this
25
25
  .getGroupId(args)
26
26
  .then((retrievedgroupId) => {
27
- return utils_1.odata.getAllItems(`${this.resource}/v1.0/groups/${retrievedgroupId}/threads/${args.options.threadId}/posts`, logger);
27
+ return utils_1.odata.getAllItems(`${this.resource}/v1.0/groups/${retrievedgroupId}/threads/${args.options.threadId}/posts`);
28
28
  })
29
29
  .then((posts) => {
30
30
  logger.log(posts);
@@ -35,7 +35,7 @@ class AadO365GroupListCommand extends GraphCommand_1.default {
35
35
  }
36
36
  let groups = [];
37
37
  utils_1.odata
38
- .getAllItems(endpoint, logger)
38
+ .getAllItems(endpoint)
39
39
  .then((_groups) => {
40
40
  groups = _groups;
41
41
  if (args.options.orphaned) {
@@ -19,7 +19,7 @@ class AadO365GroupRecycleBinItemClearCommand extends GraphCommand_1.default {
19
19
  }
20
20
  commandAction(logger, args, cb) {
21
21
  const clearO365GroupRecycleBinItems = () => {
22
- this.processRecycleBinItemsClear(logger).then(_ => cb(), (rawRes) => this.handleRejectedODataJsonPromise(rawRes, logger, cb));
22
+ this.processRecycleBinItemsClear().then(_ => cb(), (rawRes) => this.handleRejectedODataJsonPromise(rawRes, logger, cb));
23
23
  };
24
24
  if (args.options.confirm) {
25
25
  clearO365GroupRecycleBinItems();
@@ -40,12 +40,12 @@ class AadO365GroupRecycleBinItemClearCommand extends GraphCommand_1.default {
40
40
  });
41
41
  }
42
42
  }
43
- processRecycleBinItemsClear(logger) {
43
+ processRecycleBinItemsClear() {
44
44
  const filter = `?$filter=groupTypes/any(c:c+eq+'Unified')`;
45
45
  const topCount = '&$top=100';
46
46
  const endpoint = `${this.resource}/v1.0/directory/deletedItems/Microsoft.Graph.Group${filter}${topCount}`;
47
47
  return utils_1.odata
48
- .getAllItems(endpoint, logger)
48
+ .getAllItems(endpoint)
49
49
  .then((recycleBinItems) => {
50
50
  if (recycleBinItems.length === 0) {
51
51
  return Promise.resolve();
@@ -26,7 +26,7 @@ class AadO365GroupRecycleBinItemListCommand extends GraphCommand_1.default {
26
26
  const topCount = '&$top=100';
27
27
  const endpoint = `${this.resource}/v1.0/directory/deletedItems/Microsoft.Graph.Group${filter}${displayNameFilter}${mailNicknameFilter}${topCount}`;
28
28
  utils_1.odata
29
- .getAllItems(endpoint, logger)
29
+ .getAllItems(endpoint)
30
30
  .then((recycleBinItems) => {
31
31
  logger.log(recycleBinItems);
32
32
  cb();
@@ -38,7 +38,7 @@ class AadO365GroupUserListCommand extends GraphCommand_1.default {
38
38
  getOwners(logger, groupId) {
39
39
  const endpoint = `${this.resource}/v1.0/groups/${groupId}/owners?$select=id,displayName,userPrincipalName,userType`;
40
40
  return utils_1.odata
41
- .getAllItems(endpoint, logger)
41
+ .getAllItems(endpoint)
42
42
  .then(users => {
43
43
  // Currently there is a bug in the Microsoft Graph that returns Owners as
44
44
  // userType 'member'. We therefore update all returned user as owner
@@ -50,7 +50,7 @@ class AadO365GroupUserListCommand extends GraphCommand_1.default {
50
50
  }
51
51
  getMembersAndGuests(logger, groupId) {
52
52
  const endpoint = `${this.resource}/v1.0/groups/${groupId}/members?$select=id,displayName,userPrincipalName,userType`;
53
- return utils_1.odata.getAllItems(endpoint, logger);
53
+ return utils_1.odata.getAllItems(endpoint);
54
54
  }
55
55
  options() {
56
56
  const options = [
@@ -92,7 +92,7 @@ class AadO365GroupUserSetCommand extends GraphCommand_1.default {
92
92
  getOwners(logger, groupId) {
93
93
  const endpoint = `${this.resource}/v1.0/groups/${groupId}/owners?$select=id,displayName,userPrincipalName,userType`;
94
94
  return utils_1.odata
95
- .getAllItems(endpoint, logger)
95
+ .getAllItems(endpoint)
96
96
  .then(users => {
97
97
  // Currently there is a bug in the Microsoft Graph that returns Owners as
98
98
  // userType 'member'. We therefore update all returned user as owner
@@ -104,7 +104,7 @@ class AadO365GroupUserSetCommand extends GraphCommand_1.default {
104
104
  }
105
105
  getMembersAndGuests(logger, groupId) {
106
106
  const endpoint = `${this.resource}/v1.0/groups/${groupId}/members?$select=id,displayName,userPrincipalName,userType`;
107
- return utils_1.odata.getAllItems(endpoint, logger);
107
+ return utils_1.odata.getAllItems(endpoint);
108
108
  }
109
109
  options() {
110
110
  const options = [
@@ -27,7 +27,7 @@ class AadUserListCommand extends GraphCommand_1.default {
27
27
  const endpoint = args.options.deleted ? 'directory/deletedItems/microsoft.graph.user' : 'users';
28
28
  const url = `${this.resource}/v1.0/${endpoint}?$select=${properties.join(',')}${(filter.length > 0 ? '&' + filter : '')}&$top=100`;
29
29
  utils_1.odata
30
- .getAllItems(url, logger)
30
+ .getAllItems(url)
31
31
  .then((users) => {
32
32
  logger.log(users);
33
33
  cb();
@@ -37,7 +37,7 @@ class AadUserSigninListCommand extends GraphCommand_1.default {
37
37
  }
38
38
  endpoint += filter;
39
39
  utils_1.odata
40
- .getAllItems(endpoint, logger)
40
+ .getAllItems(endpoint)
41
41
  .then((signins) => {
42
42
  logger.log(signins);
43
43
  cb();
@@ -6,11 +6,11 @@ exports.default = {
6
6
  APP_DELETE: `${prefix} app delete`,
7
7
  APP_GET: `${prefix} app get`,
8
8
  APP_REMOVE: `${prefix} app remove`,
9
- APP_SET: `${prefix} app set`,
10
9
  APP_ROLE_ADD: `${prefix} app role add`,
11
10
  APP_ROLE_DELETE: `${prefix} app role delete`,
12
11
  APP_ROLE_LIST: `${prefix} app role list`,
13
12
  APP_ROLE_REMOVE: `${prefix} app role remove`,
13
+ APP_SET: `${prefix} app set`,
14
14
  APPROLEASSIGNMENT_ADD: `${prefix} approleassignment add`,
15
15
  APPROLEASSIGNMENT_LIST: `${prefix} approleassignment list`,
16
16
  APPROLEASSIGNMENT_REMOVE: `${prefix} approleassignment remove`,