@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
@@ -1,17 +1,29 @@
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 _LoginCommand_instances, _a, _LoginCommand_initTelemetry, _LoginCommand_initOptions, _LoginCommand_initValidators;
7
1
  import fs from 'fs';
2
+ import { z } from 'zod';
8
3
  import auth, { AuthType, CloudType } from '../../Auth.js';
9
- import Command, { CommandError } from '../../Command.js';
10
- import config from '../../config.js';
11
- import { misc } from '../../utils/misc.js';
12
- import commands from './commands.js';
13
- import { settingsNames } from '../../settingsNames.js';
4
+ import Command, { CommandError, globalOptionsZod } from '../../Command.js';
14
5
  import { cli } from '../../cli/cli.js';
6
+ import { settingsNames } from '../../settingsNames.js';
7
+ import { zod } from '../../utils/zod.js';
8
+ import commands from './commands.js';
9
+ const options = globalOptionsZod
10
+ .extend({
11
+ authType: zod.alias('t', z.nativeEnum(AuthType).optional()),
12
+ cloud: z.nativeEnum(CloudType).optional().default(CloudType.Public),
13
+ userName: zod.alias('u', z.string().optional()),
14
+ password: zod.alias('p', z.string().optional()),
15
+ certificateFile: zod.alias('c', z.string().optional()
16
+ .refine(filePath => !filePath || fs.existsSync(filePath), filePath => ({
17
+ message: `Certificate file ${filePath} does not exist`
18
+ }))),
19
+ certificateBase64Encoded: z.string().optional(),
20
+ thumbprint: z.string().optional(),
21
+ appId: z.string().optional(),
22
+ tenant: z.string().optional(),
23
+ secret: zod.alias('s', z.string().optional()),
24
+ connectionName: z.string().optional()
25
+ })
26
+ .strict();
15
27
  class LoginCommand extends Command {
16
28
  get name() {
17
29
  return commands.LOGIN;
@@ -19,12 +31,40 @@ class LoginCommand extends Command {
19
31
  get description() {
20
32
  return 'Log in to Microsoft 365';
21
33
  }
22
- constructor() {
23
- super();
24
- _LoginCommand_instances.add(this);
25
- __classPrivateFieldGet(this, _LoginCommand_instances, "m", _LoginCommand_initTelemetry).call(this);
26
- __classPrivateFieldGet(this, _LoginCommand_instances, "m", _LoginCommand_initOptions).call(this);
27
- __classPrivateFieldGet(this, _LoginCommand_instances, "m", _LoginCommand_initValidators).call(this);
34
+ get schema() {
35
+ return options;
36
+ }
37
+ getRefinedSchema(schema) {
38
+ return schema
39
+ .refine(options => typeof options.appId !== 'undefined' || cli.getConfig().get(settingsNames.clientId), {
40
+ message: `appId is required. TIP: use the "m365 setup" command to configure the default appId`
41
+ })
42
+ .refine(options => options.authType !== 'password' || options.userName, {
43
+ message: 'Username is required when using password authentication',
44
+ path: ['userName']
45
+ })
46
+ .refine(options => options.authType !== 'password' || options.password, {
47
+ message: 'Password is required when using password authentication',
48
+ path: ['password']
49
+ })
50
+ .refine(options => options.authType !== 'certificate' || !(options.certificateFile && options.certificateBase64Encoded), {
51
+ message: 'Specify either certificateFile or certificateBase64Encoded, but not both.',
52
+ path: ['certificateBase64Encoded']
53
+ })
54
+ .refine(options => options.authType !== 'certificate' ||
55
+ options.certificateFile ||
56
+ options.certificateBase64Encoded ||
57
+ cli.getConfig().get(settingsNames.clientCertificateFile) ||
58
+ cli.getConfig().get(settingsNames.clientCertificateBase64Encoded), {
59
+ message: 'Specify either certificateFile or certificateBase64Encoded',
60
+ path: ['certificateFile']
61
+ })
62
+ .refine(options => options.authType !== 'secret' ||
63
+ options.secret ||
64
+ cli.getConfig().get(settingsNames.clientSecret), {
65
+ message: 'Secret is required when using secret authentication',
66
+ path: ['secret']
67
+ });
28
68
  }
29
69
  async commandAction(logger, args) {
30
70
  // disconnect before re-connecting
@@ -32,13 +72,24 @@ class LoginCommand extends Command {
32
72
  await logger.logToStderr(`Logging out from Microsoft 365...`);
33
73
  }
34
74
  const deactivate = () => auth.connection.deactivate();
75
+ const getCertificate = (options) => {
76
+ // command args take precedence over settings
77
+ if (options.certificateFile) {
78
+ return fs.readFileSync(options.certificateFile).toString('base64');
79
+ }
80
+ if (options.certificateBase64Encoded) {
81
+ return options.certificateBase64Encoded;
82
+ }
83
+ return cli.getConfig().get(settingsNames.clientCertificateFile) ||
84
+ cli.getConfig().get(settingsNames.clientCertificateBase64Encoded);
85
+ };
35
86
  const login = async () => {
36
87
  if (this.verbose) {
37
88
  await logger.logToStderr(`Signing in to Microsoft 365...`);
38
89
  }
39
90
  const authType = args.options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
40
- auth.connection.appId = args.options.appId || config.cliEntraAppId;
41
- auth.connection.tenant = args.options.tenant || config.tenant;
91
+ auth.connection.appId = args.options.appId || cli.getClientId();
92
+ auth.connection.tenant = args.options.tenant || cli.getTenant();
42
93
  auth.connection.name = args.options.connectionName;
43
94
  switch (authType) {
44
95
  case 'password':
@@ -48,9 +99,9 @@ class LoginCommand extends Command {
48
99
  break;
49
100
  case 'certificate':
50
101
  auth.connection.authType = AuthType.Certificate;
51
- auth.connection.certificate = args.options.certificateBase64Encoded ? args.options.certificateBase64Encoded : fs.readFileSync(args.options.certificateFile, 'base64');
102
+ auth.connection.certificate = getCertificate(args.options);
52
103
  auth.connection.thumbprint = args.options.thumbprint;
53
- auth.connection.password = args.options.password;
104
+ auth.connection.password = args.options.password || cli.getConfig().get(settingsNames.clientCertificatePassword);
54
105
  break;
55
106
  case 'identity':
56
107
  auth.connection.authType = AuthType.Identity;
@@ -61,15 +112,10 @@ class LoginCommand extends Command {
61
112
  break;
62
113
  case 'secret':
63
114
  auth.connection.authType = AuthType.Secret;
64
- auth.connection.secret = args.options.secret;
115
+ auth.connection.secret = args.options.secret || cli.getConfig().get(settingsNames.clientSecret);
65
116
  break;
66
117
  }
67
- if (args.options.cloud) {
68
- auth.connection.cloudType = CloudType[args.options.cloud];
69
- }
70
- else {
71
- auth.connection.cloudType = CloudType.Public;
72
- }
118
+ auth.connection.cloudType = args.options.cloud;
73
119
  try {
74
120
  await auth.ensureAccessToken(auth.defaultResource, logger, this.debug);
75
121
  auth.connection.active = true;
@@ -102,79 +148,5 @@ class LoginCommand extends Command {
102
148
  await this.commandAction(logger, args);
103
149
  }
104
150
  }
105
- _a = LoginCommand, _LoginCommand_instances = new WeakSet(), _LoginCommand_initTelemetry = function _LoginCommand_initTelemetry() {
106
- this.telemetry.push((args) => {
107
- Object.assign(this.telemetryProperties, {
108
- authType: args.options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode'),
109
- cloud: args.options.cloud ?? CloudType.Public
110
- });
111
- });
112
- }, _LoginCommand_initOptions = function _LoginCommand_initOptions() {
113
- this.options.unshift({
114
- option: '-t, --authType [authType]',
115
- autocomplete: _a.allowedAuthTypes
116
- }, {
117
- option: '-u, --userName [userName]'
118
- }, {
119
- option: '-p, --password [password]'
120
- }, {
121
- option: '-c, --certificateFile [certificateFile]'
122
- }, {
123
- option: '--certificateBase64Encoded [certificateBase64Encoded]'
124
- }, {
125
- option: '--thumbprint [thumbprint]'
126
- }, {
127
- option: '--appId [appId]'
128
- }, {
129
- option: '--tenant [tenant]'
130
- }, {
131
- option: '-s, --secret [secret]'
132
- }, {
133
- option: '--cloud [cloud]',
134
- autocomplete: misc.getEnums(CloudType)
135
- }, {
136
- option: '--connectionName [connectionName]'
137
- });
138
- }, _LoginCommand_initValidators = function _LoginCommand_initValidators() {
139
- this.validators.push(async (args) => {
140
- const authType = args.options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
141
- if (authType === 'password') {
142
- if (!args.options.userName) {
143
- return 'Required option userName missing';
144
- }
145
- if (!args.options.password) {
146
- return 'Required option password missing';
147
- }
148
- }
149
- if (authType === 'certificate') {
150
- if (args.options.certificateFile && args.options.certificateBase64Encoded) {
151
- return 'Specify either certificateFile or certificateBase64Encoded, but not both.';
152
- }
153
- if (!args.options.certificateFile && !args.options.certificateBase64Encoded) {
154
- return 'Specify either certificateFile or certificateBase64Encoded';
155
- }
156
- if (args.options.certificateFile) {
157
- if (!fs.existsSync(args.options.certificateFile)) {
158
- return `File '${args.options.certificateFile}' does not exist`;
159
- }
160
- }
161
- }
162
- if (authType &&
163
- _a.allowedAuthTypes.indexOf(authType) < 0) {
164
- return `'${authType}' is not a valid authentication type. Allowed authentication types are ${_a.allowedAuthTypes.join(', ')}`;
165
- }
166
- if (authType === 'secret') {
167
- if (!args.options.secret) {
168
- return 'Required option secret missing';
169
- }
170
- }
171
- if (args.options.cloud &&
172
- typeof CloudType[args.options.cloud] === 'undefined') {
173
- return `${args.options.cloud} is not a valid value for cloud. Valid options are ${misc.getEnums(CloudType).join(', ')}`;
174
- }
175
- return true;
176
- });
177
- };
178
- LoginCommand.allowedAuthTypes = ['certificate', 'deviceCode', 'password', 'identity', 'browser', 'secret'];
179
151
  export default new LoginCommand();
180
152
  //# sourceMappingURL=login.js.map
@@ -6,12 +6,44 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
6
6
  var _SetupCommand_instances, _SetupCommand_initTelemetry, _SetupCommand_initOptions, _SetupCommand_initValidators;
7
7
  import chalk from 'chalk';
8
8
  import os from 'os';
9
+ import auth, { AuthType } from '../../Auth.js';
9
10
  import { cli } from '../../cli/cli.js';
11
+ import config from '../../config.js';
12
+ import { settingsNames } from '../../settingsNames.js';
13
+ import { accessToken } from '../../utils/accessToken.js';
14
+ import { entraApp } from '../../utils/entraApp.js';
10
15
  import { CheckStatus, formatting } from '../../utils/formatting.js';
11
16
  import { pid } from '../../utils/pid.js';
17
+ import { validation } from '../../utils/validation.js';
12
18
  import AnonymousCommand from '../base/AnonymousCommand.js';
13
19
  import commands from './commands.js';
14
20
  import { interactivePreset, powerShellPreset, scriptingPreset } from './setupPresets.js';
21
+ export var CliUsageMode;
22
+ (function (CliUsageMode) {
23
+ CliUsageMode["Interactively"] = "interactively";
24
+ CliUsageMode["Scripting"] = "scripting";
25
+ })(CliUsageMode || (CliUsageMode = {}));
26
+ export var CliExperience;
27
+ (function (CliExperience) {
28
+ CliExperience["Beginner"] = "beginner";
29
+ CliExperience["Proficient"] = "proficient";
30
+ })(CliExperience || (CliExperience = {}));
31
+ export var EntraAppConfig;
32
+ (function (EntraAppConfig) {
33
+ EntraAppConfig["Create"] = "create";
34
+ EntraAppConfig["UseExisting"] = "useExisting";
35
+ EntraAppConfig["Skip"] = "skip";
36
+ })(EntraAppConfig || (EntraAppConfig = {}));
37
+ export var NewEntraAppScopes;
38
+ (function (NewEntraAppScopes) {
39
+ NewEntraAppScopes["Minimal"] = "minimal";
40
+ NewEntraAppScopes["All"] = "all";
41
+ })(NewEntraAppScopes || (NewEntraAppScopes = {}));
42
+ export var HelpMode;
43
+ (function (HelpMode) {
44
+ HelpMode["Full"] = "full";
45
+ HelpMode["Options"] = "options";
46
+ })(HelpMode || (HelpMode = {}));
15
47
  class SetupCommand extends AnonymousCommand {
16
48
  get name() {
17
49
  return commands.SETUP;
@@ -35,11 +67,11 @@ class SetupCommand extends AnonymousCommand {
35
67
  }
36
68
  else if (args.options.scripting) {
37
69
  Object.assign(settings, scriptingPreset);
38
- if (pid.isPowerShell()) {
39
- Object.assign(settings, powerShellPreset);
40
- }
41
70
  }
42
- await this.configureSettings(settings, true, logger);
71
+ if (pid.isPowerShell()) {
72
+ Object.assign(settings, powerShellPreset);
73
+ }
74
+ await this.configureSettings({ preferences: {}, settings, silent: true, logger });
43
75
  return;
44
76
  }
45
77
  await logger.logToStderr(`Welcome to the CLI for Microsoft 365 setup!`);
@@ -47,15 +79,45 @@ class SetupCommand extends AnonymousCommand {
47
79
  await logger.logToStderr(`Please, answer the following questions and we'll define a set of settings to best match how you intend to use the CLI.`);
48
80
  await logger.logToStderr('');
49
81
  const preferences = {};
82
+ if (!args.options.skipApp) {
83
+ const entraAppConfig = {
84
+ message: 'CLI for Microsoft 365 requires a Microsoft Entra app. Do you want to create a new app registration or use an existing one?',
85
+ choices: [
86
+ { name: 'Create a new app registration', value: EntraAppConfig.Create },
87
+ { name: 'Use an existing app registration', value: EntraAppConfig.UseExisting },
88
+ { name: 'Skip configuring app registration', value: EntraAppConfig.Skip }
89
+ ]
90
+ };
91
+ preferences.entraApp = await cli.promptForSelection(entraAppConfig);
92
+ switch (preferences.entraApp) {
93
+ case EntraAppConfig.Create:
94
+ const newEntraAppScopesConfig = {
95
+ message: 'What scopes should the new app registration have?',
96
+ choices: [
97
+ { name: 'User.Read (you will need to add the necessary permissions yourself)', value: NewEntraAppScopes.Minimal },
98
+ { name: 'All (easy way to use all CLI commands)', value: NewEntraAppScopes.All }
99
+ ]
100
+ };
101
+ preferences.newEntraAppScopes = await cli.promptForSelection(newEntraAppScopesConfig);
102
+ break;
103
+ case EntraAppConfig.UseExisting:
104
+ const existingApp = await this.configureExistingEntraApp(logger);
105
+ Object.assign(preferences, existingApp);
106
+ break;
107
+ }
108
+ }
109
+ else {
110
+ preferences.entraApp = EntraAppConfig.Skip;
111
+ }
50
112
  const usageModeConfig = {
51
113
  message: 'How do you plan to use the CLI?',
52
114
  choices: [
53
- { name: 'Interactively', value: 'Interactively' },
54
- { name: 'Scripting', value: 'Scripting' }
115
+ { name: 'Interactively', value: CliUsageMode.Interactively },
116
+ { name: 'Scripting', value: CliUsageMode.Scripting }
55
117
  ]
56
118
  };
57
119
  preferences.usageMode = await cli.promptForSelection(usageModeConfig);
58
- if (preferences.usageMode === 'Scripting') {
120
+ if (preferences.usageMode === CliUsageMode.Scripting) {
59
121
  const usedInPowerShellConfig = {
60
122
  message: 'Are you going to use the CLI in PowerShell?',
61
123
  default: pid.isPowerShell()
@@ -65,33 +127,149 @@ class SetupCommand extends AnonymousCommand {
65
127
  const experienceConfig = {
66
128
  message: 'How experienced are you in using the CLI?',
67
129
  choices: [
68
- { name: 'Beginner', value: 'Beginner' },
69
- { name: 'Proficient', value: 'Proficient' }
130
+ { name: 'Beginner', value: CliExperience.Beginner },
131
+ { name: 'Proficient', value: CliExperience.Proficient }
70
132
  ]
71
133
  };
72
134
  preferences.experience = await cli.promptForSelection(experienceConfig);
73
135
  const summaryConfig = {
74
- message: this.getSummaryMessage(this.getSettings(preferences))
136
+ message: this.getSummaryMessage(preferences)
75
137
  };
76
138
  preferences.summary = await cli.promptForConfirmation(summaryConfig);
77
- if (preferences.summary) {
78
- // used only for testing. Normally, we'd get the settings from the answers
79
- /* c8 ignore next 3 */
80
- if (!settings) {
81
- settings = this.getSettings(preferences);
82
- }
83
- await logger.logToStderr('');
84
- await logger.logToStderr('Configuring settings...');
139
+ if (!preferences.summary) {
140
+ return;
141
+ }
142
+ // used only for testing. Normally, we'd get the settings from the answers
143
+ /* c8 ignore next 3 */
144
+ if (!settings) {
145
+ settings = this.getSettings(preferences);
146
+ }
147
+ await logger.logToStderr('');
148
+ await logger.logToStderr('Configuring settings...');
149
+ await logger.logToStderr('');
150
+ await this.configureSettings({ preferences, settings, silent: false, logger });
151
+ if (!this.verbose) {
85
152
  await logger.logToStderr('');
86
- await this.configureSettings(settings, false, logger);
87
- if (!this.verbose) {
88
- await logger.logToStderr('');
89
- await logger.logToStderr(chalk.green('DONE'));
153
+ await logger.logToStderr(chalk.green('DONE'));
154
+ }
155
+ }
156
+ async configureExistingEntraApp(logger) {
157
+ await logger.logToStderr('Please provide the details of the existing app registration.');
158
+ let clientCertificateFile;
159
+ let clientCertificateBase64Encoded;
160
+ let clientCertificatePassword;
161
+ const clientId = await cli.promptForInput({
162
+ message: 'Client ID:',
163
+ /* c8 ignore next */
164
+ validate: value => validation.isValidGuid(value) ? true : 'The specified value is not a valid GUID.'
165
+ });
166
+ const tenantId = await cli.promptForInput({
167
+ message: 'Tenant ID (leave common if the app is multitenant):',
168
+ default: 'common',
169
+ /* c8 ignore next */
170
+ validate: value => value === 'common' || validation.isValidGuid(value) ? true : `Tenant ID must be a valid GUID or 'common'.`
171
+ });
172
+ const clientSecret = await cli.promptForInput({
173
+ message: 'Client secret (leave empty if you use a certificate or a public client):'
174
+ });
175
+ if (!clientSecret) {
176
+ clientCertificateFile = await cli.promptForInput({
177
+ message: `Path to the client certificate file (leave empty if you want to specify a base64-encoded certificate string):`
178
+ });
179
+ if (!clientCertificateFile) {
180
+ clientCertificateBase64Encoded = await cli.promptForInput({
181
+ message: `Base64-encoded certificate string (leave empty if you don't connect using a certificate):`
182
+ });
183
+ }
184
+ if (clientCertificateFile || clientCertificateBase64Encoded) {
185
+ clientCertificatePassword = await cli.promptForInput({
186
+ message: 'Password for the client certificate (leave empty if the certificate is not password-protected):'
187
+ });
90
188
  }
91
189
  }
190
+ return {
191
+ clientId,
192
+ tenantId,
193
+ clientSecret,
194
+ clientCertificateFile,
195
+ clientCertificateBase64Encoded,
196
+ clientCertificatePassword
197
+ };
92
198
  }
93
- getSummaryMessage(settings) {
199
+ async createNewEntraApp(preferences, logger) {
200
+ if (!await cli.promptForConfirmation({
201
+ message: 'CLI for Microsoft 365 will now sign in to your Microsoft 365 tenant as Microsoft Azure CLI to create a new app registration. Continue?',
202
+ default: false
203
+ })) {
204
+ throw 'Cancelled';
205
+ }
206
+ // setup auth
207
+ auth.connection.authType = AuthType.Browser;
208
+ // Microsoft Azure CLI app ID
209
+ auth.connection.appId = '04b07795-8ddb-461a-bbee-02f9e1bf7b46';
210
+ auth.connection.tenant = 'common';
211
+ await auth.ensureAccessToken(auth.defaultResource, logger, this.debug);
212
+ auth.connection.active = true;
213
+ const options = {
214
+ allowPublicClientFlows: true,
215
+ apisDelegated: (preferences.newEntraAppScopes === NewEntraAppScopes.All ? config.allScopes : config.minimalScopes).join(','),
216
+ implicitFlow: false,
217
+ multitenant: false,
218
+ name: 'CLI for Microsoft 365',
219
+ platform: 'publicClient',
220
+ redirectUris: 'http://localhost,https://localhost,https://login.microsoftonline.com/common/oauth2/nativeclient'
221
+ };
222
+ const apis = await entraApp.resolveApis({
223
+ options,
224
+ logger,
225
+ verbose: this.verbose,
226
+ debug: this.debug
227
+ });
228
+ const appInfo = await entraApp.createAppRegistration({
229
+ options,
230
+ apis,
231
+ logger,
232
+ verbose: this.verbose,
233
+ debug: this.debug
234
+ });
235
+ appInfo.tenantId = accessToken.getTenantIdFromAccessToken(auth.connection.accessTokens[auth.defaultResource].accessToken);
236
+ await entraApp.grantAdminConsent({
237
+ appInfo,
238
+ appPermissions: entraApp.appPermissions,
239
+ adminConsent: true,
240
+ logger,
241
+ debug: this.debug
242
+ });
243
+ return appInfo;
244
+ }
245
+ getSummaryMessage(preferences) {
94
246
  const messageLines = [`Based on your preferences, we'll configure the following settings:`];
247
+ switch (preferences.entraApp) {
248
+ case EntraAppConfig.Create:
249
+ messageLines.push(`- Entra app: Create a new app registration with ${preferences.newEntraAppScopes} scopes`);
250
+ break;
251
+ case EntraAppConfig.UseExisting:
252
+ messageLines.push(`- Entra app: use existing`);
253
+ messageLines.push(` - Client ID: ${preferences.clientId}`);
254
+ messageLines.push(` - Tenant ID: ${preferences.tenantId}`);
255
+ if (preferences.clientSecret) {
256
+ messageLines.push(` - Client secret: ${preferences.clientSecret}`);
257
+ }
258
+ if (preferences.clientCertificateFile) {
259
+ messageLines.push(` - Client certificate file: ${preferences.clientCertificateFile}`);
260
+ }
261
+ if (preferences.clientCertificateBase64Encoded) {
262
+ messageLines.push(` - Client certificate base64-encoded: ${preferences.clientCertificateBase64Encoded}`);
263
+ }
264
+ if (preferences.clientCertificatePassword) {
265
+ messageLines.push(` - Client certificate password: ${preferences.clientCertificatePassword}`);
266
+ }
267
+ break;
268
+ case EntraAppConfig.Skip:
269
+ messageLines.push(`- Entra app: skip`);
270
+ break;
271
+ }
272
+ const settings = this.getSettings(preferences);
95
273
  for (const [key, value] of Object.entries(settings)) {
96
274
  messageLines.push(`- ${key}: ${value}`);
97
275
  }
@@ -101,10 +279,10 @@ class SetupCommand extends AnonymousCommand {
101
279
  getSettings(answers) {
102
280
  const settings = {};
103
281
  switch (answers.usageMode) {
104
- case 'Interactively':
282
+ case CliUsageMode.Interactively:
105
283
  Object.assign(settings, interactivePreset);
106
284
  break;
107
- case 'Scripting':
285
+ case CliUsageMode.Scripting:
108
286
  Object.assign(settings, scriptingPreset);
109
287
  break;
110
288
  }
@@ -112,16 +290,60 @@ class SetupCommand extends AnonymousCommand {
112
290
  Object.assign(settings, powerShellPreset);
113
291
  }
114
292
  switch (answers.experience) {
115
- case 'Beginner':
116
- settings.helpMode = 'full';
293
+ case CliExperience.Beginner:
294
+ settings.helpMode = HelpMode.Full;
117
295
  break;
118
- case 'Proficient':
119
- settings.helpMode = 'options';
296
+ case CliExperience.Proficient:
297
+ settings.helpMode = HelpMode.Options;
298
+ break;
299
+ }
300
+ switch (answers.entraApp) {
301
+ case EntraAppConfig.Create:
302
+ settings.authType = 'browser';
303
+ break;
304
+ case EntraAppConfig.UseExisting:
305
+ if (answers.clientSecret) {
306
+ settings.authType = 'secret';
307
+ break;
308
+ }
309
+ if (answers.clientCertificateFile || answers.clientCertificateBase64Encoded) {
310
+ settings.authType = 'certificate';
311
+ break;
312
+ }
313
+ settings.authType = 'browser';
120
314
  break;
121
315
  }
122
316
  return settings;
123
317
  }
124
- async configureSettings(settings, silent, logger) {
318
+ async configureSettings({ preferences, settings, silent, logger }) {
319
+ switch (preferences.entraApp) {
320
+ case EntraAppConfig.Create:
321
+ if (this.verbose) {
322
+ await logger.logToStderr('Creating a new Entra app...');
323
+ }
324
+ const appSettings = await this.createNewEntraApp(preferences, logger);
325
+ Object.assign(settings, {
326
+ clientId: appSettings.appId,
327
+ tenantId: appSettings.tenantId
328
+ });
329
+ cli.getConfig().delete(settingsNames.clientSecret);
330
+ cli.getConfig().delete(settingsNames.clientCertificateFile);
331
+ cli.getConfig().delete(settingsNames.clientCertificateBase64Encoded);
332
+ cli.getConfig().delete(settingsNames.clientCertificatePassword);
333
+ break;
334
+ case EntraAppConfig.UseExisting:
335
+ Object.assign(settings, {
336
+ clientId: preferences.clientId,
337
+ tenantId: preferences.tenantId,
338
+ clientSecret: preferences.clientSecret,
339
+ clientCertificateFile: preferences.clientCertificateFile,
340
+ clientCertificateBase64Encoded: preferences.clientCertificateBase64Encoded,
341
+ clientCertificatePassword: preferences.clientCertificatePassword
342
+ });
343
+ break;
344
+ case EntraAppConfig.Skip:
345
+ break;
346
+ }
125
347
  if (this.debug) {
126
348
  await logger.logToStderr('Configuring settings...');
127
349
  await logger.logToStderr(JSON.stringify(settings, null, 2));
@@ -137,13 +359,14 @@ class SetupCommand extends AnonymousCommand {
137
359
  _SetupCommand_instances = new WeakSet(), _SetupCommand_initTelemetry = function _SetupCommand_initTelemetry() {
138
360
  this.telemetry.push((args) => {
139
361
  const properties = {
140
- interactive: args.options.interactive,
141
- scripting: args.options.scripting
362
+ interactive: !!args.options.interactive,
363
+ scripting: !!args.options.scripting,
364
+ skipApp: !!args.options.skipApp
142
365
  };
143
366
  Object.assign(this.telemetryProperties, properties);
144
367
  });
145
368
  }, _SetupCommand_initOptions = function _SetupCommand_initOptions() {
146
- this.options.unshift({ option: '--interactive' }, { option: '--scripting' });
369
+ this.options.unshift({ option: '--interactive' }, { option: '--scripting' }, { option: '--skipApp' });
147
370
  }, _SetupCommand_initValidators = function _SetupCommand_initValidators() {
148
371
  this.validators.push(async (args) => {
149
372
  if (args.options.interactive && args.options.scripting) {
@@ -1,7 +1,7 @@
1
- import auth, { AuthType } from '../../../Auth.js';
2
- import commands from '../commands.js';
3
- import Command, { CommandError } from '../../../Command.js';
4
1
  import assert from 'assert';
2
+ import auth from '../../../Auth.js';
3
+ import Command, { CommandError } from '../../../Command.js';
4
+ import commands from '../commands.js';
5
5
  class ConnectionListCommand extends Command {
6
6
  get name() {
7
7
  return commands.LIST;
@@ -19,7 +19,7 @@ class ConnectionListCommand extends Command {
19
19
  return {
20
20
  name: connection.name,
21
21
  connectedAs: connection.identityName,
22
- authType: AuthType[connection.authType],
22
+ authType: connection.authType,
23
23
  active: isCurrentConnection
24
24
  };
25
25
  }).sort((a, b) => {
@@ -3,7 +3,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
3
3
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
4
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
5
  };
6
- var _ConnectionRemoveCommand_instances, _ConnectionRemoveCommand_initTelemetry, _ConnectionRemoveCommand_initOptions;
6
+ var _ConnectionRemoveCommand_instances, _ConnectionRemoveCommand_initTelemetry, _ConnectionRemoveCommand_initOptions, _ConnectionRemoveCommand_initTypes;
7
7
  import auth from '../../../Auth.js';
8
8
  import commands from '../commands.js';
9
9
  import Command, { CommandError } from '../../../Command.js';
@@ -20,6 +20,7 @@ class ConnectionRemoveCommand extends Command {
20
20
  _ConnectionRemoveCommand_instances.add(this);
21
21
  __classPrivateFieldGet(this, _ConnectionRemoveCommand_instances, "m", _ConnectionRemoveCommand_initTelemetry).call(this);
22
22
  __classPrivateFieldGet(this, _ConnectionRemoveCommand_instances, "m", _ConnectionRemoveCommand_initOptions).call(this);
23
+ __classPrivateFieldGet(this, _ConnectionRemoveCommand_instances, "m", _ConnectionRemoveCommand_initTypes).call(this);
23
24
  }
24
25
  async commandAction(logger, args) {
25
26
  const deleteConnection = async () => {
@@ -53,7 +54,7 @@ class ConnectionRemoveCommand extends Command {
53
54
  _ConnectionRemoveCommand_instances = new WeakSet(), _ConnectionRemoveCommand_initTelemetry = function _ConnectionRemoveCommand_initTelemetry() {
54
55
  this.telemetry.push((args) => {
55
56
  Object.assign(this.telemetryProperties, {
56
- force: (!(!args.options.force)).toString()
57
+ force: !!args.options.force
57
58
  });
58
59
  });
59
60
  }, _ConnectionRemoveCommand_initOptions = function _ConnectionRemoveCommand_initOptions() {
@@ -62,6 +63,9 @@ _ConnectionRemoveCommand_instances = new WeakSet(), _ConnectionRemoveCommand_ini
62
63
  }, {
63
64
  option: '-f, --force'
64
65
  });
66
+ }, _ConnectionRemoveCommand_initTypes = function _ConnectionRemoveCommand_initTypes() {
67
+ this.types.string.push('name');
68
+ this.types.boolean.push('force');
65
69
  };
66
70
  export default new ConnectionRemoveCommand();
67
71
  //# sourceMappingURL=connection-remove.js.map