@pnp/cli-microsoft365 8.1.0-beta.3dec9fa → 8.1.0-beta.96dc207

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 (105) hide show
  1. package/allCommands.json +1 -1
  2. package/allCommandsFull.json +1 -1
  3. package/dist/Auth.js +20 -21
  4. package/dist/Command.js +50 -5
  5. package/dist/cli/cli.js +115 -39
  6. package/dist/config.js +60 -5
  7. package/dist/m365/base/SpoCommand.js +1 -1
  8. package/dist/m365/cli/commands/cli-consent.js +2 -2
  9. package/dist/m365/cli/commands/cli-doctor.js +2 -2
  10. package/dist/m365/cli/commands/cli-reconsent.js +2 -3
  11. package/dist/m365/cli/commands/config/config-set.js +12 -3
  12. package/dist/m365/commands/login.js +74 -102
  13. package/dist/m365/commands/setup.js +256 -33
  14. package/dist/m365/connection/commands/connection-list.js +4 -4
  15. package/dist/m365/connection/commands/connection-remove.js +6 -2
  16. package/dist/m365/connection/commands/connection-set.js +4 -1
  17. package/dist/m365/connection/commands/connection-use.js +25 -4
  18. package/dist/m365/entra/commands/app/app-add.js +52 -288
  19. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-remove.js +123 -0
  20. package/dist/m365/entra/commands/group/group-set.js +256 -0
  21. package/dist/m365/entra/commands/m365group/m365group-user-add.js +109 -32
  22. package/dist/m365/entra/commands/m365group/m365group-user-set.js +159 -84
  23. package/dist/m365/entra/commands/multitenant/multitenant-add.js +65 -0
  24. package/dist/m365/entra/commands/multitenant/multitenant-remove.js +118 -0
  25. package/dist/m365/entra/commands/multitenant/multitenant-set.js +72 -0
  26. package/dist/m365/entra/commands.js +6 -0
  27. package/dist/m365/flow/commands/flow-get.js +1 -1
  28. package/dist/m365/onenote/commands/notebook/notebook-add.js +132 -0
  29. package/dist/m365/onenote/commands.js +1 -0
  30. package/dist/m365/pa/commands/app/app-export.js +13 -7
  31. package/dist/m365/spe/ContainerTypeProperties.js +2 -0
  32. package/dist/m365/spe/commands/containertype/containertype-list.js +49 -0
  33. package/dist/m365/spe/commands.js +2 -1
  34. package/dist/m365/spo/commands/applicationcustomizer/applicationcustomizer-get.js +16 -21
  35. package/dist/m365/spo/commands/commandset/commandset-get.js +31 -17
  36. package/dist/m365/spo/commands/file/file-roleassignment-add.js +1 -1
  37. package/dist/m365/spo/commands/file/file-roleinheritance-break.js +1 -1
  38. package/dist/m365/spo/commands/file/file-roleinheritance-reset.js +1 -1
  39. package/dist/m365/spo/commands/folder/folder-retentionlabel-ensure.js +1 -1
  40. package/dist/m365/spo/commands/folder/folder-sharinglink-get.js +86 -0
  41. package/dist/m365/spo/commands/folder/folder-sharinglink-list.js +110 -0
  42. package/dist/m365/spo/commands/list/ListInstance.js +6 -1
  43. package/dist/m365/spo/commands/list/list-get.js +9 -3
  44. package/dist/m365/spo/commands/list/list-roleassignment-add.js +46 -21
  45. package/dist/m365/spo/commands/list/list-roleassignment-remove.js +48 -46
  46. package/dist/m365/spo/commands/site/site-get.js +12 -16
  47. package/dist/m365/spo/commands/tenant/tenant-applicationcustomizer-get.js +19 -5
  48. package/dist/m365/spo/commands/tenant/tenant-commandset-get.js +20 -6
  49. package/dist/m365/spo/commands.js +2 -0
  50. package/dist/m365/teams/commands/message/message-restore.js +106 -0
  51. package/dist/m365/teams/commands.js +1 -0
  52. package/dist/settingsNames.js +7 -1
  53. package/dist/utils/drive.js +61 -0
  54. package/dist/utils/entraApp.js +283 -0
  55. package/dist/utils/formatting.js +16 -0
  56. package/dist/utils/spo.js +69 -6
  57. package/dist/utils/zod.js +124 -0
  58. package/docs/docs/_clisettings.mdx +6 -0
  59. package/docs/docs/cmd/connection/connection-use.mdx +8 -2
  60. package/docs/docs/cmd/entra/enterpriseapp/enterpriseapp-remove.mdx +65 -0
  61. package/docs/docs/cmd/entra/group/group-add.mdx +0 -4
  62. package/docs/docs/cmd/entra/group/group-set.mdx +89 -0
  63. package/docs/docs/cmd/entra/m365group/m365group-user-add.mdx +28 -10
  64. package/docs/docs/cmd/entra/m365group/m365group-user-set.mdx +35 -11
  65. package/docs/docs/cmd/entra/multitenant/multitenant-add.mdx +107 -0
  66. package/docs/docs/cmd/entra/multitenant/multitenant-remove.mdx +58 -0
  67. package/docs/docs/cmd/entra/multitenant/multitenant-set.mdx +53 -0
  68. package/docs/docs/cmd/flow/flow-get.mdx +149 -283
  69. package/docs/docs/cmd/onenote/notebook/notebook-add.mdx +169 -0
  70. package/docs/docs/cmd/pa/app/app-export.mdx +15 -9
  71. package/docs/docs/cmd/planner/plan/plan-remove.mdx +1 -1
  72. package/docs/docs/cmd/setup.mdx +16 -3
  73. package/docs/docs/cmd/spe/containertype/containertype-list.mdx +102 -0
  74. package/docs/docs/cmd/spo/app/app-uninstall.mdx +1 -1
  75. package/docs/docs/cmd/spo/applicationcustomizer/applicationcustomizer-get.mdx +87 -38
  76. package/docs/docs/cmd/spo/applicationcustomizer/applicationcustomizer-list.mdx +22 -28
  77. package/docs/docs/cmd/spo/commandset/commandset-get.mdx +75 -24
  78. package/docs/docs/cmd/spo/commandset/commandset-list.mdx +26 -32
  79. package/docs/docs/cmd/spo/file/file-retentionlabel-ensure.mdx +1 -1
  80. package/docs/docs/cmd/spo/file/file-roleassignment-add.mdx +2 -2
  81. package/docs/docs/cmd/spo/file/file-roleassignment-remove.mdx +1 -1
  82. package/docs/docs/cmd/spo/file/file-roleinheritance-break.mdx +1 -1
  83. package/docs/docs/cmd/spo/file/file-roleinheritance-reset.mdx +1 -1
  84. package/docs/docs/cmd/spo/folder/folder-retentionlabel-ensure.mdx +2 -2
  85. package/docs/docs/cmd/spo/folder/folder-sharinglink-get.mdx +110 -0
  86. package/docs/docs/cmd/spo/folder/folder-sharinglink-list.mdx +114 -0
  87. package/docs/docs/cmd/spo/list/list-get.mdx +6 -0
  88. package/docs/docs/cmd/spo/list/list-roleassignment-add.mdx +15 -3
  89. package/docs/docs/cmd/spo/list/list-roleassignment-remove.mdx +15 -3
  90. package/docs/docs/cmd/spo/listitem/listitem-retentionlabel-ensure.mdx +4 -4
  91. package/docs/docs/cmd/spo/listitem/listitem-retentionlabel-remove.mdx +1 -1
  92. package/docs/docs/cmd/spo/listitem/listitem-roleassignment-add.mdx +9 -9
  93. package/docs/docs/cmd/spo/listitem/listitem-roleassignment-remove.mdx +7 -7
  94. package/docs/docs/cmd/spo/site/site-recyclebinitem-list.mdx +1 -1
  95. package/docs/docs/cmd/spo/tenant/tenant-applicationcustomizer-get.mdx +79 -30
  96. package/docs/docs/cmd/spo/tenant/tenant-applicationcustomizer-list.mdx +20 -19
  97. package/docs/docs/cmd/spo/tenant/tenant-commandset-get.mdx +84 -38
  98. package/docs/docs/cmd/spo/tenant/tenant-commandset-list.mdx +20 -19
  99. package/docs/docs/cmd/spo/web/web-roleassignment-add.mdx +1 -1
  100. package/docs/docs/cmd/spo/web/web-roleassignment-remove.mdx +1 -1
  101. package/docs/docs/cmd/teams/meeting/meeting-list.mdx +7 -3
  102. package/docs/docs/cmd/teams/message/message-remove.mdx +2 -1
  103. package/docs/docs/cmd/teams/message/message-restore.mdx +62 -0
  104. package/npm-shrinkwrap.json +1002 -1147
  105. package/package.json +26 -23
package/dist/Auth.js CHANGED
@@ -1,31 +1,30 @@
1
1
  import { AzureCloudInstance } from '@azure/msal-common';
2
+ import assert from 'assert';
2
3
  import { CommandError } from './Command.js';
3
4
  import { FileTokenStorage } from './auth/FileTokenStorage.js';
4
5
  import { msalCachePlugin } from './auth/msalCachePlugin.js';
5
6
  import { cli } from './cli/cli.js';
6
- import config from './config.js';
7
7
  import request from './request.js';
8
8
  import { settingsNames } from './settingsNames.js';
9
- import { browserUtil } from './utils/browserUtil.js';
10
9
  import * as accessTokenUtil from './utils/accessToken.js';
11
- import assert from 'assert';
10
+ import { browserUtil } from './utils/browserUtil.js';
12
11
  export var CloudType;
13
12
  (function (CloudType) {
14
- CloudType[CloudType["Public"] = 0] = "Public";
15
- CloudType[CloudType["USGov"] = 1] = "USGov";
16
- CloudType[CloudType["USGovHigh"] = 2] = "USGovHigh";
17
- CloudType[CloudType["USGovDoD"] = 3] = "USGovDoD";
18
- CloudType[CloudType["China"] = 4] = "China";
13
+ CloudType["Public"] = "Public";
14
+ CloudType["USGov"] = "USGov";
15
+ CloudType["USGovHigh"] = "USGovHigh";
16
+ CloudType["USGovDoD"] = "USGovDoD";
17
+ CloudType["China"] = "China";
19
18
  })(CloudType || (CloudType = {}));
20
19
  export class Connection {
21
20
  constructor() {
22
21
  this.active = false;
23
22
  this.authType = AuthType.DeviceCode;
24
23
  this.certificateType = CertificateType.Unknown;
24
+ // ID of the tenant where the Microsoft Entra app is registered; common if multi-tenant
25
+ this.tenant = 'common';
25
26
  this.cloudType = CloudType.Public;
26
27
  this.accessTokens = {};
27
- this.appId = config.cliEntraAppId;
28
- this.tenant = config.tenant;
29
28
  this.cloudType = CloudType.Public;
30
29
  }
31
30
  deactivate() {
@@ -44,18 +43,18 @@ export class Connection {
44
43
  this.thumbprint = undefined;
45
44
  this.spoUrl = undefined;
46
45
  this.spoTenantId = undefined;
47
- this.appId = config.cliEntraAppId;
48
- this.tenant = config.tenant;
46
+ this.appId = cli.getClientId();
47
+ this.tenant = cli.getTenant();
49
48
  }
50
49
  }
51
50
  export var AuthType;
52
51
  (function (AuthType) {
53
- AuthType[AuthType["DeviceCode"] = 0] = "DeviceCode";
54
- AuthType[AuthType["Password"] = 1] = "Password";
55
- AuthType[AuthType["Certificate"] = 2] = "Certificate";
56
- AuthType[AuthType["Identity"] = 3] = "Identity";
57
- AuthType[AuthType["Browser"] = 4] = "Browser";
58
- AuthType[AuthType["Secret"] = 5] = "Secret";
52
+ AuthType["DeviceCode"] = "deviceCode";
53
+ AuthType["Password"] = "password";
54
+ AuthType["Certificate"] = "certificate";
55
+ AuthType["Identity"] = "identity";
56
+ AuthType["Browser"] = "browser";
57
+ AuthType["Secret"] = "secret";
59
58
  })(AuthType || (AuthType = {}));
60
59
  export var CertificateType;
61
60
  (function (CertificateType) {
@@ -691,7 +690,7 @@ export class Auth {
691
690
  const allConnections = await this.getAllConnections();
692
691
  const connection = allConnections.find(i => i.name === name);
693
692
  if (!connection) {
694
- throw new CommandError(`The connection '${name}' cannot be found`);
693
+ throw new CommandError(`The connection '${name}' cannot be found.`);
695
694
  }
696
695
  return connection;
697
696
  }
@@ -702,7 +701,7 @@ export class Auth {
702
701
  const details = {
703
702
  connectionName: connection.name,
704
703
  connectedAs: connection.identityName,
705
- authType: AuthType[connection.authType],
704
+ authType: connection.authType,
706
705
  appId: connection.appId,
707
706
  appTenant: connection.tenant,
708
707
  cloudType: CloudType[connection.cloudType]
@@ -710,7 +709,7 @@ export class Auth {
710
709
  return details;
711
710
  }
712
711
  }
713
- Auth.cloudEndpoints = [];
712
+ Auth.cloudEndpoints = {};
714
713
  Auth.initialize();
715
714
  export default new Auth();
716
715
  //# sourceMappingURL=Auth.js.map
package/dist/Command.js CHANGED
@@ -5,6 +5,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
5
5
  };
6
6
  var _Command_instances, _Command_initTelemetry, _Command_initOptions, _Command_initValidators;
7
7
  import os from 'os';
8
+ import { z } from 'zod';
8
9
  import auth from './Auth.js';
9
10
  import { cli } from './cli/cli.js';
10
11
  import request from './request.js';
@@ -13,6 +14,7 @@ import { telemetry } from './telemetry.js';
13
14
  import { accessToken } from './utils/accessToken.js';
14
15
  import { md } from './utils/md.js';
15
16
  import { prompt } from './utils/prompt.js';
17
+ import { zod } from './utils/zod.js';
16
18
  export class CommandError {
17
19
  constructor(message, code) {
18
20
  this.message = message;
@@ -25,10 +27,26 @@ export class CommandErrorWithOutput {
25
27
  this.stderr = stderr;
26
28
  }
27
29
  }
30
+ export const globalOptionsZod = z.object({
31
+ query: z.string().optional(),
32
+ output: zod.alias('o', z.enum(['csv', 'json', 'md', 'text', 'none']).optional()),
33
+ debug: z.boolean().default(false),
34
+ verbose: z.boolean().default(false)
35
+ });
28
36
  class Command {
29
37
  get allowedOutputs() {
30
38
  return ['csv', 'json', 'md', 'text', 'none'];
31
39
  }
40
+ get schema() {
41
+ return undefined;
42
+ }
43
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
44
+ getRefinedSchema(schema) {
45
+ return undefined;
46
+ }
47
+ getSchemaToParse() {
48
+ return this.getRefinedSchema(this.schema) ?? this.schema;
49
+ }
32
50
  constructor() {
33
51
  // These functions must be defined with # so that they're truly private
34
52
  // otherwise you'll get a ts2415 error (Types have separate declarations of
@@ -48,6 +66,9 @@ class Command {
48
66
  string: []
49
67
  };
50
68
  this.validators = [];
69
+ // metadata for command's options
70
+ // used for building telemetry
71
+ this.optionsInfo = [];
51
72
  __classPrivateFieldGet(this, _Command_instances, "m", _Command_initTelemetry).call(this);
52
73
  __classPrivateFieldGet(this, _Command_instances, "m", _Command_initOptions).call(this);
53
74
  __classPrivateFieldGet(this, _Command_instances, "m", _Command_initValidators).call(this);
@@ -90,9 +111,7 @@ class Command {
90
111
  prompted = true;
91
112
  await cli.error('🌶️ Provide values for the following parameters:');
92
113
  }
93
- const answer = optionInfo.autocomplete !== undefined
94
- ? await prompt.forSelection({ message: `${optionInfo.name}: `, choices: optionInfo.autocomplete.map((choice) => { return { name: choice, value: choice }; }) })
95
- : await prompt.forInput({ message: `${optionInfo.name}: ` });
114
+ const answer = await cli.promptForValue(optionInfo);
96
115
  args.options[optionInfo.name] = answer;
97
116
  }
98
117
  if (prompted) {
@@ -410,8 +429,34 @@ class Command {
410
429
  return '';
411
430
  }
412
431
  getTelemetryProperties(args) {
413
- this.telemetry.forEach(t => t(args));
414
- return this.telemetryProperties;
432
+ if (this.schema) {
433
+ const telemetryProperties = {};
434
+ this.optionsInfo.forEach(o => {
435
+ if (o.required) {
436
+ return;
437
+ }
438
+ if (typeof args.options[o.name] === 'undefined') {
439
+ return;
440
+ }
441
+ switch (o.type) {
442
+ case 'string':
443
+ telemetryProperties[o.name] = o.autocomplete ? args.options[o.name] : typeof args.options[o.name] !== 'undefined';
444
+ break;
445
+ case 'boolean':
446
+ telemetryProperties[o.name] = args.options[o.name];
447
+ break;
448
+ case 'number':
449
+ telemetryProperties[o.name] = typeof args.options[o.name] !== 'undefined';
450
+ break;
451
+ }
452
+ ;
453
+ });
454
+ return telemetryProperties;
455
+ }
456
+ else {
457
+ this.telemetry.forEach(t => t(args));
458
+ return this.telemetryProperties;
459
+ }
415
460
  }
416
461
  async getTextOutput(logStatement) {
417
462
  // display object as a list of key-value pairs
package/dist/cli/cli.js CHANGED
@@ -1,22 +1,24 @@
1
1
  import Configstore from 'configstore';
2
2
  import fs from 'fs';
3
- import minimist from 'minimist';
4
3
  import { createRequire } from 'module';
5
4
  import os from 'os';
6
5
  import path from 'path';
7
6
  import { fileURLToPath, pathToFileURL } from 'url';
7
+ import yargs from 'yargs-parser';
8
+ import { ZodError } from 'zod';
8
9
  import Command, { CommandError } from '../Command.js';
9
10
  import config from '../config.js';
10
11
  import request from '../request.js';
11
12
  import { settingsNames } from '../settingsNames.js';
12
13
  import { telemetry } from '../telemetry.js';
13
14
  import { app } from '../utils/app.js';
15
+ import { browserUtil } from '../utils/browserUtil.js';
14
16
  import { formatting } from '../utils/formatting.js';
15
17
  import { md } from '../utils/md.js';
16
- import { validation } from '../utils/validation.js';
17
18
  import { prompt } from '../utils/prompt.js';
19
+ import { validation } from '../utils/validation.js';
20
+ import { zod } from '../utils/zod.js';
18
21
  import { timings } from './timings.js';
19
- import { browserUtil } from '../utils/browserUtil.js';
20
22
  const require = createRequire(import.meta.url);
21
23
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
22
24
  let _config;
@@ -34,6 +36,14 @@ const defaultHelpMode = 'options';
34
36
  const defaultHelpTarget = 'console';
35
37
  const helpModes = ['options', 'examples', 'remarks', 'response', 'full'];
36
38
  const helpTargets = ['console', 'web'];
39
+ const yargsConfiguration = {
40
+ 'parse-numbers': true,
41
+ 'strip-aliased': true,
42
+ 'strip-dashed': true,
43
+ 'dot-notation': false,
44
+ 'boolean-negation': true,
45
+ 'camel-case-expansion': false
46
+ };
37
47
  function getConfig() {
38
48
  if (!_config) {
39
49
  _config = new Configstore(config.configstoreName);
@@ -49,6 +59,12 @@ function getSettingWithDefaultValue(settingName, defaultValue) {
49
59
  return configuredValue;
50
60
  }
51
61
  }
62
+ function getClientId() {
63
+ return cli.getSettingWithDefaultValue(settingsNames.clientId, process.env.CLIMICROSOFT365_ENTRAAPPID || process.env.CLIMICROSOFT365_AADAPPID);
64
+ }
65
+ function getTenant() {
66
+ return cli.getSettingWithDefaultValue(settingsNames.tenantId, process.env.CLIMICROSOFT365_TENANT || 'common');
67
+ }
52
68
  async function execute(rawArgs) {
53
69
  const start = process.hrtime.bigint();
54
70
  // for completion commands we also need information about commands' options
@@ -64,7 +80,7 @@ async function execute(rawArgs) {
64
80
  rawArgs.shift();
65
81
  }
66
82
  // parse args to see if a command has been specified
67
- const parsedArgs = minimist(rawArgs);
83
+ const parsedArgs = yargs(rawArgs);
68
84
  // load command
69
85
  await cli.loadCommandFromArgs(parsedArgs._);
70
86
  if (cli.commandToExecute) {
@@ -77,8 +93,7 @@ async function execute(rawArgs) {
77
93
  };
78
94
  }
79
95
  catch (e) {
80
- const optionsWithoutShorts = removeShortOptions({ options: parsedArgs });
81
- return cli.closeWithError(e.message, optionsWithoutShorts, false);
96
+ return cli.closeWithError(e.message, { options: parsedArgs }, false);
82
97
  }
83
98
  }
84
99
  else {
@@ -126,18 +141,54 @@ async function execute(rawArgs) {
126
141
  if (cli.optionsFromArgs.options.output === undefined) {
127
142
  cli.optionsFromArgs.options.output = cli.getSettingWithDefaultValue(settingsNames.output, 'json');
128
143
  }
129
- const startValidation = process.hrtime.bigint();
130
- const validationResult = await cli.commandToExecute.command.validate(cli.optionsFromArgs, cli.commandToExecute);
131
- const endValidation = process.hrtime.bigint();
132
- timings.validation.push(Number(endValidation - startValidation));
133
- if (validationResult !== true) {
134
- return cli.closeWithError(validationResult, cli.optionsFromArgs, true);
144
+ let finalArgs = cli.optionsFromArgs.options;
145
+ if (cli.commandToExecute?.command.schema) {
146
+ while (true) {
147
+ const startValidation = process.hrtime.bigint();
148
+ const result = cli.commandToExecute.command.getSchemaToParse().safeParse(cli.optionsFromArgs.options);
149
+ const endValidation = process.hrtime.bigint();
150
+ timings.validation.push(Number(endValidation - startValidation));
151
+ if (result.success) {
152
+ finalArgs = result.data;
153
+ break;
154
+ }
155
+ else {
156
+ const hasNonRequiredErrors = result.error.errors.some(e => e.code !== 'invalid_type' || e.received !== 'undefined');
157
+ const shouldPrompt = cli.getSettingWithDefaultValue(settingsNames.prompt, true);
158
+ if (hasNonRequiredErrors === false &&
159
+ shouldPrompt) {
160
+ await cli.error('🌶️ Provide values for the following parameters:');
161
+ for (const error of result.error.errors) {
162
+ const optionInfo = cli.commandToExecute.options.find(o => o.name === error.path.join('.'));
163
+ const answer = await cli.promptForValue(optionInfo);
164
+ cli.optionsFromArgs.options[error.path.join('.')] = answer;
165
+ }
166
+ }
167
+ else {
168
+ result.error.errors.forEach(e => {
169
+ if (e.code === 'invalid_type' &&
170
+ e.received === 'undefined') {
171
+ e.message = `Required option not specified`;
172
+ }
173
+ });
174
+ return cli.closeWithError(result.error, cli.optionsFromArgs, true);
175
+ }
176
+ }
177
+ }
178
+ }
179
+ else {
180
+ const startValidation = process.hrtime.bigint();
181
+ const validationResult = await cli.commandToExecute.command.validate(cli.optionsFromArgs, cli.commandToExecute);
182
+ const endValidation = process.hrtime.bigint();
183
+ timings.validation.push(Number(endValidation - startValidation));
184
+ if (validationResult !== true) {
185
+ return cli.closeWithError(validationResult, cli.optionsFromArgs, true);
186
+ }
135
187
  }
136
- cli.optionsFromArgs = removeShortOptions(cli.optionsFromArgs);
137
188
  const end = process.hrtime.bigint();
138
189
  timings.core.push(Number(end - start));
139
190
  try {
140
- await cli.executeCommand(cli.commandToExecute.command, cli.optionsFromArgs);
191
+ await cli.executeCommand(cli.commandToExecute.command, { options: finalArgs });
141
192
  const endTotal = process.hrtime.bigint();
142
193
  timings.total.push(Number(endTotal - start));
143
194
  await printTimings(rawArgs);
@@ -347,12 +398,14 @@ async function loadCommandFromFile(commandFileUrl) {
347
398
  catch { }
348
399
  }
349
400
  function getCommandInfo(command, filePath = '', helpFilePath = '') {
401
+ const options = command.schema ? zod.schemaToOptions(command.schema) : getCommandOptions(command);
402
+ command.optionsInfo = options;
350
403
  return {
351
404
  aliases: command.alias(),
352
405
  name: command.name,
353
406
  description: command.description,
354
407
  command: command,
355
- options: getCommandOptions(command),
408
+ options,
356
409
  defaultProperties: command.defaultProperties(),
357
410
  file: filePath,
358
411
  help: helpFilePath
@@ -387,36 +440,43 @@ function getCommandOptions(command) {
387
440
  return options;
388
441
  }
389
442
  function getCommandOptionsFromArgs(args, commandInfo) {
390
- const minimistOptions = {
391
- alias: {}
443
+ const yargsOptions = {
444
+ alias: {},
445
+ configuration: yargsConfiguration
392
446
  };
393
447
  let argsToParse = args;
394
448
  if (commandInfo) {
395
- const commandTypes = commandInfo.command.types;
396
- if (commandTypes) {
397
- minimistOptions.string = commandTypes.string;
398
- // minimist will parse unused boolean options to 'false' (unused options => options that are not included in the args)
399
- // But in the CLI booleans are nullable. They can can be true, false or undefined.
400
- // For this reason we only pass boolean types that are actually used as arg.
401
- minimistOptions.boolean = commandTypes.boolean.filter(optionName => args.some(arg => `--${optionName}` === arg || `-${optionName}` === arg));
402
- }
403
- minimistOptions.alias = {};
449
+ if (commandInfo.command.schema) {
450
+ yargsOptions.string = commandInfo.options.filter(o => o.type === 'string').map(o => o.name);
451
+ yargsOptions.boolean = commandInfo.options.filter(o => o.type === 'boolean').map(o => o.name);
452
+ yargsOptions.number = commandInfo.options.filter(o => o.type === 'number').map(o => o.name);
453
+ argsToParse = getRewrittenArgs(args, yargsOptions.boolean);
454
+ }
455
+ else {
456
+ const commandTypes = commandInfo.command.types;
457
+ if (commandTypes) {
458
+ yargsOptions.string = commandTypes.string;
459
+ // minimist will parse unused boolean options to 'false' (unused options => options that are not included in the args)
460
+ // But in the CLI booleans are nullable. They can can be true, false or undefined.
461
+ // For this reason we only pass boolean types that are actually used as arg.
462
+ yargsOptions.boolean = commandTypes.boolean.filter(optionName => args.some(arg => `--${optionName}` === arg || `-${optionName}` === arg));
463
+ }
464
+ argsToParse = getRewrittenArgs(args, commandTypes.boolean);
465
+ }
404
466
  commandInfo.options.forEach(option => {
405
467
  if (option.short && option.long) {
406
- minimistOptions.alias[option.short] = option.long;
468
+ yargsOptions.alias[option.long] = option.short;
407
469
  }
408
470
  });
409
- argsToParse = getRewrittenArgs(args, commandTypes);
410
471
  }
411
- return minimist(argsToParse, minimistOptions);
472
+ return yargs(argsToParse, yargsOptions);
412
473
  }
413
474
  /**
414
475
  * Rewrites arguments (if necessary) before passing them into minimist.
415
476
  * Currently only boolean values are checked and fixed.
416
477
  * Args are only checked and rewritten if the option has been added to the 'types.boolean' array.
417
478
  */
418
- function getRewrittenArgs(args, commandTypes) {
419
- const booleanTypes = commandTypes.boolean;
479
+ function getRewrittenArgs(args, booleanTypes) {
420
480
  if (booleanTypes.length === 0) {
421
481
  return args;
422
482
  }
@@ -722,6 +782,9 @@ async function closeWithError(error, args, showHelpIfEnabled = false) {
722
782
  return process.exit(exitCode);
723
783
  }
724
784
  let errorMessage = error instanceof CommandError ? error.message : error;
785
+ if (error instanceof ZodError) {
786
+ errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(os.EOL);
787
+ }
725
788
  if ((!args.options.output || args.options.output === 'json') &&
726
789
  !cli.getSettingWithDefaultValue(settingsNames.printErrorsAsPlainText, true)) {
727
790
  errorMessage = JSON.stringify({ error: errorMessage });
@@ -760,6 +823,16 @@ async function error(message, ...optionalParams) {
760
823
  console.error(message, ...optionalParams);
761
824
  }
762
825
  }
826
+ async function promptForValue(optionInfo) {
827
+ return optionInfo.autocomplete !== undefined
828
+ ? await prompt.forSelection({
829
+ message: `${optionInfo.name}: `,
830
+ choices: optionInfo.autocomplete.map((choice) => {
831
+ return { name: choice, value: choice };
832
+ })
833
+ })
834
+ : await prompt.forInput({ message: `${optionInfo.name}: ` });
835
+ }
763
836
  async function promptForSelection(config) {
764
837
  const answer = await prompt.forSelection(config);
765
838
  await cli.error('');
@@ -770,6 +843,11 @@ async function promptForConfirmation(config) {
770
843
  await cli.error('');
771
844
  return answer;
772
845
  }
846
+ async function promptForInput(config) {
847
+ const answer = await prompt.forInput(config);
848
+ await cli.error('');
849
+ return answer;
850
+ }
773
851
  async function handleMultipleResultsFound(message, values) {
774
852
  const prompt = cli.getSettingWithDefaultValue(settingsNames.prompt, true);
775
853
  if (!prompt) {
@@ -780,13 +858,6 @@ async function handleMultipleResultsFound(message, values) {
780
858
  const response = await cli.promptForSelection({ message: `Please choose one:`, choices });
781
859
  return values[response];
782
860
  }
783
- function removeShortOptions(args) {
784
- const filteredArgs = JSON.parse(JSON.stringify(args));
785
- const optionsToRemove = Object.getOwnPropertyNames(args.options)
786
- .filter(option => option.length === 1 || option === '--');
787
- optionsToRemove.forEach(option => delete filteredArgs.options[option]);
788
- return filteredArgs;
789
- }
790
861
  function loadOptionValuesFromFiles(args) {
791
862
  const optionNames = Object.getOwnPropertyNames(args.options);
792
863
  optionNames.forEach(option => {
@@ -811,7 +882,9 @@ export const cli = {
811
882
  closeWithError,
812
883
  commands,
813
884
  commandToExecute,
885
+ getClientId,
814
886
  getConfig,
887
+ getTenant,
815
888
  currentCommandName,
816
889
  error,
817
890
  execute,
@@ -830,7 +903,10 @@ export const cli = {
830
903
  optionsFromArgs,
831
904
  printAvailableCommands,
832
905
  promptForConfirmation,
906
+ promptForInput,
833
907
  promptForSelection,
834
- shouldTrimOutput
908
+ promptForValue,
909
+ shouldTrimOutput,
910
+ yargsConfiguration
835
911
  };
836
912
  //# sourceMappingURL=cli.js.map
package/dist/config.js CHANGED
@@ -1,10 +1,65 @@
1
- import { app } from "./utils/app.js";
2
- const cliEntraAppId = '31359c7f-bd7e-475c-86db-fdb8c937548e';
1
+ import { app } from './utils/app.js';
3
2
  export default {
3
+ allScopes: [
4
+ 'https://graph.windows.net/Directory.AccessAsUser.All',
5
+ 'https://management.azure.com/user_impersonation',
6
+ 'https://admin.services.crm.dynamics.com/user_impersonation',
7
+ 'https://graph.microsoft.com/AppCatalog.ReadWrite.All',
8
+ 'https://graph.microsoft.com/AuditLog.Read.All',
9
+ 'https://graph.microsoft.com/Bookings.Read.All',
10
+ 'https://graph.microsoft.com/Calendars.Read',
11
+ 'https://graph.microsoft.com/ChannelMember.ReadWrite.All',
12
+ 'https://graph.microsoft.com/ChannelMessage.Read.All',
13
+ 'https://graph.microsoft.com/ChannelMessage.ReadWrite',
14
+ 'https://graph.microsoft.com/ChannelMessage.Send',
15
+ 'https://graph.microsoft.com/ChannelSettings.ReadWrite.All',
16
+ 'https://graph.microsoft.com/Chat.ReadWrite',
17
+ 'https://graph.microsoft.com/Directory.AccessAsUser.All',
18
+ 'https://graph.microsoft.com/Directory.ReadWrite.All',
19
+ 'https://graph.microsoft.com/ExternalConnection.ReadWrite.All',
20
+ 'https://graph.microsoft.com/ExternalItem.ReadWrite.All',
21
+ 'https://graph.microsoft.com/Group.ReadWrite.All',
22
+ 'https://graph.microsoft.com/IdentityProvider.ReadWrite.All',
23
+ 'https://graph.microsoft.com/InformationProtectionPolicy.Read',
24
+ 'https://graph.microsoft.com/Mail.Read.Shared',
25
+ 'https://graph.microsoft.com/Mail.ReadWrite',
26
+ 'https://graph.microsoft.com/Mail.Send',
27
+ 'https://graph.microsoft.com/Notes.ReadWrite.All',
28
+ 'https://graph.microsoft.com/OnlineMeetingArtifact.Read.All',
29
+ 'https://graph.microsoft.com/OnlineMeetings.ReadWrite',
30
+ 'https://graph.microsoft.com/OnlineMeetingTranscript.Read.All',
31
+ 'https://graph.microsoft.com/PeopleSettings.ReadWrite.All',
32
+ 'https://graph.microsoft.com/Place.Read.All',
33
+ 'https://graph.microsoft.com/Policy.Read.All',
34
+ 'https://graph.microsoft.com/RecordsManagement.ReadWrite.All',
35
+ 'https://graph.microsoft.com/Reports.Read.All',
36
+ 'https://graph.microsoft.com/RoleAssignmentSchedule.ReadWrite.Directory',
37
+ 'https://graph.microsoft.com/RoleEligibilitySchedule.Read.Directory',
38
+ 'https://graph.microsoft.com/SecurityEvents.Read.All',
39
+ 'https://graph.microsoft.com/ServiceHealth.Read.All',
40
+ 'https://graph.microsoft.com/ServiceMessage.Read.All',
41
+ 'https://graph.microsoft.com/ServiceMessageViewpoint.Write',
42
+ 'https://graph.microsoft.com/Sites.Read.All',
43
+ 'https://graph.microsoft.com/Tasks.ReadWrite',
44
+ 'https://graph.microsoft.com/Team.Create',
45
+ 'https://graph.microsoft.com/TeamMember.ReadWrite.All',
46
+ 'https://graph.microsoft.com/TeamsAppInstallation.ReadWriteForUser',
47
+ 'https://graph.microsoft.com/TeamSettings.ReadWrite.All',
48
+ 'https://graph.microsoft.com/TeamsTab.ReadWrite.All',
49
+ 'https://graph.microsoft.com/User.Invite.All',
50
+ 'https://manage.office.com/ActivityFeed.Read',
51
+ 'https://manage.office.com/ServiceHealth.Read',
52
+ 'https://analysis.windows.net/powerbi/api/Dataset.Read.All',
53
+ 'https://api.powerapps.com//User',
54
+ 'https://microsoft.sharepoint-df.com/AllSites.FullControl',
55
+ 'https://microsoft.sharepoint-df.com/TermStore.ReadWrite.All',
56
+ 'https://microsoft.sharepoint-df.com/User.ReadWrite.All'
57
+ ],
4
58
  applicationName: `CLI for Microsoft 365 v${app.packageJson().version}`,
5
59
  delimiter: 'm365\$',
6
- cliEntraAppId: process.env.CLIMICROSOFT365_ENTRAAPPID || process.env.CLIMICROSOFT365_AADAPPID || cliEntraAppId,
7
- tenant: process.env.CLIMICROSOFT365_TENANT || 'common',
8
- configstoreName: 'cli-m365-config'
60
+ configstoreName: 'cli-m365-config',
61
+ minimalScopes: [
62
+ 'https://graph.microsoft.com/User.Read'
63
+ ]
9
64
  };
10
65
  //# sourceMappingURL=config.js.map
@@ -94,7 +94,7 @@ export default class SpoCommand extends Command {
94
94
  catch (error) {
95
95
  throw new CommandError(error);
96
96
  }
97
- if (auth.connection.active && AuthType[auth.connection.authType] === AuthType[AuthType.Secret]) {
97
+ if (auth.connection.active && auth.connection.authType === AuthType.Secret) {
98
98
  throw new CommandError(`SharePoint does not support authentication using client ID and secret. Please use a different login type to use SharePoint commands.`);
99
99
  }
100
100
  await super.action(logger, args);
@@ -4,7 +4,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _CliConsentCommand_instances, _CliConsentCommand_initTelemetry, _CliConsentCommand_initOptions, _CliConsentCommand_initValidators;
7
- import config from '../../../config.js';
7
+ import { cli } from '../../../cli/cli.js';
8
8
  import AnonymousCommand from '../../base/AnonymousCommand.js';
9
9
  import commands from '../commands.js';
10
10
  class CliConsentCommand extends AnonymousCommand {
@@ -30,7 +30,7 @@ class CliConsentCommand extends AnonymousCommand {
30
30
  scope = 'https://api.yammer.com/user_impersonation';
31
31
  break;
32
32
  }
33
- await logger.log(`To consent permissions for executing ${args.options.service} commands, navigate in your web browser to https://login.microsoftonline.com/${config.tenant}/oauth2/v2.0/authorize?client_id=${config.cliEntraAppId}&response_type=code&scope=${encodeURIComponent(scope)}`);
33
+ await logger.log(`To consent permissions for executing ${args.options.service} commands, navigate in your web browser to https://login.microsoftonline.com/${cli.getTenant()}/oauth2/v2.0/authorize?client_id=${cli.getClientId()}&response_type=code&scope=${encodeURIComponent(scope)}`);
34
34
  }
35
35
  async action(logger, args) {
36
36
  await this.initAction(args, logger);
@@ -1,5 +1,5 @@
1
1
  import os from 'os';
2
- import auth, { AuthType } from '../../../Auth.js';
2
+ import auth from '../../../Auth.js';
3
3
  import { cli } from '../../../cli/cli.js';
4
4
  import Command from '../../../Command.js';
5
5
  import { app } from '../../../utils/app.js';
@@ -33,7 +33,7 @@ class CliDoctorCommand extends Command {
33
33
  nodeVersion: process.version,
34
34
  cliAadAppId: auth.connection.appId,
35
35
  cliAadAppTenant: validation.isValidGuid(auth.connection.tenant) ? 'single' : auth.connection.tenant,
36
- authMode: AuthType[auth.connection.authType],
36
+ authMode: auth.connection.authType,
37
37
  cliEnvironment: process.env.CLIMICROSOFT365_ENV ? process.env.CLIMICROSOFT365_ENV : '',
38
38
  cliConfig: cli.getConfig().all,
39
39
  roles: roles,
@@ -1,5 +1,4 @@
1
1
  import { cli } from '../../../cli/cli.js';
2
- import config from '../../../config.js';
3
2
  import { settingsNames } from '../../../settingsNames.js';
4
3
  import { browserUtil } from '../../../utils/browserUtil.js';
5
4
  import AnonymousCommand from '../../base/AnonymousCommand.js';
@@ -12,9 +11,9 @@ class CliReconsentCommand extends AnonymousCommand {
12
11
  return 'Returns URL to open in the browser to re-consent CLI for Microsoft 365 Microsoft Entra permissions';
13
12
  }
14
13
  async commandAction(logger) {
15
- const url = `https://login.microsoftonline.com/${config.tenant}/oauth2/authorize?client_id=${config.cliEntraAppId}&response_type=code&prompt=admin_consent`;
14
+ const url = `https://login.microsoftonline.com/${cli.getTenant()}/oauth2/authorize?client_id=${cli.getClientId()}&response_type=code&prompt=admin_consent`;
16
15
  if (cli.getSettingWithDefaultValue(settingsNames.autoOpenLinksInBrowser, false) === false) {
17
- await logger.log(`To re-consent the PnP Microsoft 365 Management Shell Microsoft Entra application navigate in your web browser to ${url}`);
16
+ await logger.log(`To re-consent your Microsoft Entra application, navigate in your web browser to ${url}.`);
18
17
  return;
19
18
  }
20
19
  await logger.log(`Opening the following page in your browser: ${url}`);
@@ -4,8 +4,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
6
  var _CliConfigSetCommand_instances, _a, _CliConfigSetCommand_initTelemetry, _CliConfigSetCommand_initOptions, _CliConfigSetCommand_initValidators;
7
+ import { AuthType } from "../../../../Auth.js";
7
8
  import { cli } from "../../../../cli/cli.js";
8
9
  import { settingsNames } from "../../../../settingsNames.js";
10
+ import { validation } from "../../../../utils/validation.js";
9
11
  import AnonymousCommand from "../../../base/AnonymousCommand.js";
10
12
  import commands from "../../commands.js";
11
13
  class CliConfigSetCommand extends AnonymousCommand {
@@ -82,15 +84,22 @@ _a = CliConfigSetCommand, _CliConfigSetCommand_instances = new WeakSet(), _CliCo
82
84
  cli.helpModes.indexOf(args.options.value) === -1) {
83
85
  return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${cli.helpModes.join(', ')}`;
84
86
  }
85
- const allowedAuthTypes = ['certificate', 'deviceCode', 'password', 'identity', 'browser', 'secret'];
86
87
  if (args.options.key === settingsNames.authType &&
87
- allowedAuthTypes.indexOf(args.options.value) === -1) {
88
- return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${allowedAuthTypes.join(', ')}`;
88
+ !Object.values(AuthType).map(String).includes(args.options.value)) {
89
+ return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${Object.values(AuthType).join(', ')}`;
89
90
  }
90
91
  if (args.options.key === settingsNames.helpTarget &&
91
92
  !cli.helpTargets.includes(args.options.value)) {
92
93
  return `${args.options.value} is not a valid value for the option ${args.options.key}. Allowed values: ${cli.helpTargets.join(', ')}`;
93
94
  }
95
+ if (args.options.key === settingsNames.clientId &&
96
+ !validation.isValidGuid(args.options.value)) {
97
+ return `${args.options.value} is not a valid value for the option ${args.options.key}. The value has to be a valid GUID.`;
98
+ }
99
+ if (args.options.key === settingsNames.tenantId &&
100
+ !(args.options.value === 'common' || validation.isValidGuid(args.options.value))) {
101
+ return `${args.options.value} is not a valid value for the option ${args.options.key}. The value has to be a valid GUID or 'common'.`;
102
+ }
94
103
  return true;
95
104
  });
96
105
  };