@pnp/cli-microsoft365 9.0.0-beta.e69e8d0 → 9.0.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 (71) hide show
  1. package/allCommands.json +1 -1
  2. package/allCommandsFull.json +1 -1
  3. package/dist/Auth.js +11 -12
  4. package/dist/Command.js +1 -3
  5. package/dist/cli/cli.js +68 -14
  6. package/dist/config.js +60 -5
  7. package/dist/m365/app/commands/permission/permission-add.js +9 -9
  8. package/dist/m365/base/SpoCommand.js +1 -1
  9. package/dist/m365/cli/commands/cli-consent.js +2 -2
  10. package/dist/m365/cli/commands/cli-doctor.js +2 -2
  11. package/dist/m365/cli/commands/cli-reconsent.js +2 -3
  12. package/dist/m365/cli/commands/config/config-set.js +12 -3
  13. package/dist/m365/commands/login.js +38 -14
  14. package/dist/m365/commands/setup.js +256 -33
  15. package/dist/m365/commands/status.js +2 -2
  16. package/dist/m365/connection/commands/connection-list.js +4 -4
  17. package/dist/m365/entra/commands/app/app-add.js +52 -288
  18. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-add.js +13 -13
  19. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-get.js +18 -18
  20. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-list.js +1 -1
  21. package/dist/m365/entra/commands/enterpriseapp/enterpriseapp-remove.js +123 -0
  22. package/dist/m365/entra/commands/group/group-set.js +256 -0
  23. package/dist/m365/entra/commands/group/group-user-list.js +4 -4
  24. package/dist/m365/entra/commands/m365group/m365group-conversation-post-list.js +4 -4
  25. package/dist/m365/entra/commands/m365group/m365group-recyclebinitem-list.js +3 -3
  26. package/dist/m365/entra/commands/m365group/m365group-user-list.js +9 -6
  27. package/dist/m365/entra/commands.js +3 -0
  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/outlook/commands/message/message-get.js +11 -11
  31. package/dist/m365/spfx/commands/project/DeployWorkflow.js +1 -1
  32. package/dist/m365/spfx/commands/project/project-github-workflow-add.js +10 -1
  33. package/dist/m365/spo/commands/file/file-copy.js +34 -55
  34. package/dist/m365/spo/commands/folder/folder-set.js +4 -0
  35. package/dist/m365/spo/commands/list/list-list.js +4 -1
  36. package/dist/m365/spo/commands/site/site-appcatalog-remove.js +24 -48
  37. package/dist/m365/spo/commands/site/site-get.js +12 -16
  38. package/dist/m365/spo/commands/site/site-remove.js +7 -1
  39. package/dist/m365/spo/commands/tenant/tenant-recyclebinitem-restore.js +22 -2
  40. package/dist/m365/spo/commands.js +1 -0
  41. package/dist/m365/teams/commands/message/message-restore.js +106 -0
  42. package/dist/m365/teams/commands.js +1 -0
  43. package/dist/settingsNames.js +7 -1
  44. package/dist/utils/entraApp.js +283 -0
  45. package/dist/utils/spo.js +0 -74
  46. package/docs/docs/_clisettings.mdx +6 -0
  47. package/docs/docs/cmd/app/permission/permission-add.mdx +5 -5
  48. package/docs/docs/cmd/entra/enterpriseapp/enterpriseapp-add.mdx +12 -12
  49. package/docs/docs/cmd/entra/enterpriseapp/enterpriseapp-get.mdx +14 -14
  50. package/docs/docs/cmd/entra/enterpriseapp/enterpriseapp-list.mdx +5 -5
  51. package/docs/docs/cmd/entra/enterpriseapp/enterpriseapp-remove.mdx +65 -0
  52. package/docs/docs/cmd/entra/group/group-add.mdx +0 -4
  53. package/docs/docs/cmd/entra/group/group-set.mdx +89 -0
  54. package/docs/docs/cmd/entra/group/group-user-list.mdx +7 -7
  55. package/docs/docs/cmd/entra/m365group/m365group-conversation-post-list.mdx +5 -5
  56. package/docs/docs/cmd/entra/m365group/m365group-recyclebinitem-list.mdx +3 -3
  57. package/docs/docs/cmd/entra/m365group/m365group-user-list.mdx +1 -1
  58. package/docs/docs/cmd/onenote/notebook/notebook-add.mdx +169 -0
  59. package/docs/docs/cmd/outlook/message/message-get.mdx +5 -5
  60. package/docs/docs/cmd/setup.mdx +16 -3
  61. package/docs/docs/cmd/spfx/project/project-github-workflow-add.mdx +12 -11
  62. package/docs/docs/cmd/spo/file/file-copy.mdx +12 -119
  63. package/docs/docs/cmd/spo/folder/folder-set.mdx +6 -0
  64. package/docs/docs/cmd/spo/list/list-list.mdx +7 -5
  65. package/docs/docs/cmd/spo/site/site-appcatalog-remove.mdx +2 -11
  66. package/docs/docs/cmd/spo/site/site-remove.mdx +3 -0
  67. package/docs/docs/cmd/spo/tenant/tenant-recyclebinitem-restore.mdx +49 -2
  68. package/docs/docs/cmd/teams/message/message-remove.mdx +2 -1
  69. package/docs/docs/cmd/teams/message/message-restore.mdx +62 -0
  70. package/npm-shrinkwrap.json +0 -1
  71. package/package.json +2 -3
package/dist/Auth.js CHANGED
@@ -4,7 +4,6 @@ import { CommandError } from './Command.js';
4
4
  import { FileTokenStorage } from './auth/FileTokenStorage.js';
5
5
  import { msalCachePlugin } from './auth/msalCachePlugin.js';
6
6
  import { cli } from './cli/cli.js';
7
- import config from './config.js';
8
7
  import request from './request.js';
9
8
  import { settingsNames } from './settingsNames.js';
10
9
  import * as accessTokenUtil from './utils/accessToken.js';
@@ -22,10 +21,10 @@ export class Connection {
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) {
@@ -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]
package/dist/Command.js CHANGED
@@ -111,9 +111,7 @@ class Command {
111
111
  prompted = true;
112
112
  await cli.error('🌶️ Provide values for the following parameters:');
113
113
  }
114
- const answer = optionInfo.autocomplete !== undefined
115
- ? await prompt.forSelection({ message: `${optionInfo.name}: `, choices: optionInfo.autocomplete.map((choice) => { return { name: choice, value: choice }; }) })
116
- : await prompt.forInput({ message: `${optionInfo.name}: ` });
114
+ const answer = await cli.promptForValue(optionInfo);
117
115
  args.options[optionInfo.name] = answer;
118
116
  }
119
117
  if (prompted) {
package/dist/cli/cli.js CHANGED
@@ -36,6 +36,14 @@ const defaultHelpMode = 'options';
36
36
  const defaultHelpTarget = 'console';
37
37
  const helpModes = ['options', 'examples', 'remarks', 'response', 'full'];
38
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
+ };
39
47
  function getConfig() {
40
48
  if (!_config) {
41
49
  _config = new Configstore(config.configstoreName);
@@ -51,6 +59,12 @@ function getSettingWithDefaultValue(settingName, defaultValue) {
51
59
  return configuredValue;
52
60
  }
53
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
+ }
54
68
  async function execute(rawArgs) {
55
69
  const start = process.hrtime.bigint();
56
70
  // for completion commands we also need information about commands' options
@@ -129,14 +143,38 @@ async function execute(rawArgs) {
129
143
  }
130
144
  let finalArgs = cli.optionsFromArgs.options;
131
145
  if (cli.commandToExecute?.command.schema) {
132
- const startValidation = process.hrtime.bigint();
133
- const result = cli.commandToExecute.command.getSchemaToParse().safeParse(cli.optionsFromArgs.options);
134
- const endValidation = process.hrtime.bigint();
135
- timings.validation.push(Number(endValidation - startValidation));
136
- if (!result.success) {
137
- return cli.closeWithError(result.error, cli.optionsFromArgs, true);
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
+ }
138
177
  }
139
- finalArgs = result.data;
140
178
  }
141
179
  else {
142
180
  const startValidation = process.hrtime.bigint();
@@ -404,11 +442,7 @@ function getCommandOptions(command) {
404
442
  function getCommandOptionsFromArgs(args, commandInfo) {
405
443
  const yargsOptions = {
406
444
  alias: {},
407
- configuration: {
408
- "parse-numbers": false,
409
- "strip-aliased": true,
410
- "strip-dashed": true
411
- }
445
+ configuration: yargsConfiguration
412
446
  };
413
447
  let argsToParse = args;
414
448
  if (commandInfo) {
@@ -749,7 +783,7 @@ async function closeWithError(error, args, showHelpIfEnabled = false) {
749
783
  }
750
784
  let errorMessage = error instanceof CommandError ? error.message : error;
751
785
  if (error instanceof ZodError) {
752
- errorMessage = error.errors.map(e => `${e.path}: ${e.message}`).join(os.EOL);
786
+ errorMessage = error.errors.map(e => `${e.path.join('.')}: ${e.message}`).join(os.EOL);
753
787
  }
754
788
  if ((!args.options.output || args.options.output === 'json') &&
755
789
  !cli.getSettingWithDefaultValue(settingsNames.printErrorsAsPlainText, true)) {
@@ -789,6 +823,16 @@ async function error(message, ...optionalParams) {
789
823
  console.error(message, ...optionalParams);
790
824
  }
791
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
+ }
792
836
  async function promptForSelection(config) {
793
837
  const answer = await prompt.forSelection(config);
794
838
  await cli.error('');
@@ -799,6 +843,11 @@ async function promptForConfirmation(config) {
799
843
  await cli.error('');
800
844
  return answer;
801
845
  }
846
+ async function promptForInput(config) {
847
+ const answer = await prompt.forInput(config);
848
+ await cli.error('');
849
+ return answer;
850
+ }
802
851
  async function handleMultipleResultsFound(message, values) {
803
852
  const prompt = cli.getSettingWithDefaultValue(settingsNames.prompt, true);
804
853
  if (!prompt) {
@@ -833,7 +882,9 @@ export const cli = {
833
882
  closeWithError,
834
883
  commands,
835
884
  commandToExecute,
885
+ getClientId,
836
886
  getConfig,
887
+ getTenant,
837
888
  currentCommandName,
838
889
  error,
839
890
  execute,
@@ -852,7 +903,10 @@ export const cli = {
852
903
  optionsFromArgs,
853
904
  printAvailableCommands,
854
905
  promptForConfirmation,
906
+ promptForInput,
855
907
  promptForSelection,
856
- shouldTrimOutput
908
+ promptForValue,
909
+ shouldTrimOutput,
910
+ yargsConfiguration
857
911
  };
858
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 || 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
@@ -33,12 +33,12 @@ class AppPermissionAddCommand extends AppCommand {
33
33
  const appObject = await this.getAppObject();
34
34
  const servicePrincipals = await odata.getAllItems(`${this.resource}/v1.0/myorganization/servicePrincipals?$select=appId,appRoles,id,oauth2PermissionScopes,servicePrincipalNames`);
35
35
  const appPermissions = [];
36
- if (args.options.delegatedPermissions) {
37
- const delegatedPermissions = await this.getRequiredResourceAccessForApis(servicePrincipals, args.options.delegatedPermissions, ScopeType.Scope, appPermissions, logger);
36
+ if (args.options.delegatedPermission) {
37
+ const delegatedPermissions = await this.getRequiredResourceAccessForApis(servicePrincipals, args.options.delegatedPermission, ScopeType.Scope, appPermissions, logger);
38
38
  this.addPermissionsToResourceArray(delegatedPermissions, appObject.requiredResourceAccess);
39
39
  }
40
- if (args.options.applicationPermissions) {
41
- const applicationPermissions = await this.getRequiredResourceAccessForApis(servicePrincipals, args.options.applicationPermissions, ScopeType.Role, appPermissions, logger);
40
+ if (args.options.applicationPermission) {
41
+ const applicationPermissions = await this.getRequiredResourceAccessForApis(servicePrincipals, args.options.applicationPermission, ScopeType.Role, appPermissions, logger);
42
42
  this.addPermissionsToResourceArray(applicationPermissions, appObject.requiredResourceAccess);
43
43
  }
44
44
  const addPermissionsRequestOptions = {
@@ -198,17 +198,17 @@ _AppPermissionAddCommand_instances = new WeakSet(), _AppPermissionAddCommand_ini
198
198
  this.telemetry.push((args) => {
199
199
  Object.assign(this.telemetryProperties, {
200
200
  appId: typeof args.options.appId !== 'undefined',
201
- applicationPermissions: typeof args.options.applicationPermissions !== 'undefined',
202
- delegatedPermissions: typeof args.options.delegatedPermissions !== 'undefined',
201
+ applicationPermission: typeof args.options.applicationPermission !== 'undefined',
202
+ delegatedPermission: typeof args.options.delegatedPermission !== 'undefined',
203
203
  grantAdminConsent: !!args.options.grantAdminConsent
204
204
  });
205
205
  });
206
206
  }, _AppPermissionAddCommand_initOptions = function _AppPermissionAddCommand_initOptions() {
207
- this.options.unshift({ option: '--appId [appId]' }, { option: '--applicationPermissions [applicationPermissions]' }, { option: '--delegatedPermissions [delegatedPermissions]' }, { option: '--grantAdminConsent' });
207
+ this.options.unshift({ option: '--appId [appId]' }, { option: '--applicationPermission [applicationPermission]' }, { option: '--delegatedPermission [delegatedPermission]' }, { option: '--grantAdminConsent' });
208
208
  }, _AppPermissionAddCommand_initOptionSets = function _AppPermissionAddCommand_initOptionSets() {
209
209
  this.optionSets.push({
210
- options: ['applicationPermissions', 'delegatedPermissions'],
211
- runsWhen: (args) => args.options.delegatedPermissions === undefined && args.options.applicationPermissions === undefined
210
+ options: ['applicationPermission', 'delegatedPermission'],
211
+ runsWhen: (args) => args.options.delegatedPermission === undefined && args.options.applicationPermission === undefined
212
212
  });
213
213
  };
214
214
  export default new AppPermissionAddCommand();
@@ -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
  };
@@ -3,13 +3,12 @@ import { z } from 'zod';
3
3
  import auth, { AuthType, CloudType } from '../../Auth.js';
4
4
  import Command, { CommandError, globalOptionsZod } from '../../Command.js';
5
5
  import { cli } from '../../cli/cli.js';
6
- import config from '../../config.js';
7
6
  import { settingsNames } from '../../settingsNames.js';
8
7
  import { zod } from '../../utils/zod.js';
9
8
  import commands from './commands.js';
10
9
  const options = globalOptionsZod
11
10
  .extend({
12
- authType: zod.alias('t', z.enum(['certificate', 'deviceCode', 'password', 'identity', 'browser', 'secret']).optional()),
11
+ authType: zod.alias('t', z.nativeEnum(AuthType).optional()),
13
12
  cloud: z.nativeEnum(CloudType).optional().default(CloudType.Public),
14
13
  userName: zod.alias('u', z.string().optional()),
15
14
  password: zod.alias('p', z.string().optional()),
@@ -37,20 +36,34 @@ class LoginCommand extends Command {
37
36
  }
38
37
  getRefinedSchema(schema) {
39
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
+ })
40
42
  .refine(options => options.authType !== 'password' || options.userName, {
41
- message: 'Username is required when using password authentication'
43
+ message: 'Username is required when using password authentication',
44
+ path: ['userName']
42
45
  })
43
46
  .refine(options => options.authType !== 'password' || options.password, {
44
- message: 'Password is required when using password authentication'
47
+ message: 'Password is required when using password authentication',
48
+ path: ['password']
45
49
  })
46
50
  .refine(options => options.authType !== 'certificate' || !(options.certificateFile && options.certificateBase64Encoded), {
47
- message: 'Specify either certificateFile or certificateBase64Encoded, but not both.'
51
+ message: 'Specify either certificateFile or certificateBase64Encoded, but not both.',
52
+ path: ['certificateBase64Encoded']
48
53
  })
49
- .refine(options => options.authType !== 'certificate' || options.certificateFile || options.certificateBase64Encoded, {
50
- message: 'Specify either certificateFile or certificateBase64Encoded'
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']
51
61
  })
52
- .refine(options => options.authType !== 'secret' || options.secret, {
53
- message: 'Secret is required when using secret authentication'
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']
54
67
  });
55
68
  }
56
69
  async commandAction(logger, args) {
@@ -59,13 +72,24 @@ class LoginCommand extends Command {
59
72
  await logger.logToStderr(`Logging out from Microsoft 365...`);
60
73
  }
61
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
+ };
62
86
  const login = async () => {
63
87
  if (this.verbose) {
64
88
  await logger.logToStderr(`Signing in to Microsoft 365...`);
65
89
  }
66
90
  const authType = args.options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
67
- auth.connection.appId = args.options.appId || config.cliEntraAppId;
68
- 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();
69
93
  auth.connection.name = args.options.connectionName;
70
94
  switch (authType) {
71
95
  case 'password':
@@ -75,9 +99,9 @@ class LoginCommand extends Command {
75
99
  break;
76
100
  case 'certificate':
77
101
  auth.connection.authType = AuthType.Certificate;
78
- auth.connection.certificate = args.options.certificateBase64Encoded ? args.options.certificateBase64Encoded : fs.readFileSync(args.options.certificateFile, 'base64');
102
+ auth.connection.certificate = getCertificate(args.options);
79
103
  auth.connection.thumbprint = args.options.thumbprint;
80
- auth.connection.password = args.options.password;
104
+ auth.connection.password = args.options.password || cli.getConfig().get(settingsNames.clientCertificatePassword);
81
105
  break;
82
106
  case 'identity':
83
107
  auth.connection.authType = AuthType.Identity;
@@ -88,7 +112,7 @@ class LoginCommand extends Command {
88
112
  break;
89
113
  case 'secret':
90
114
  auth.connection.authType = AuthType.Secret;
91
- auth.connection.secret = args.options.secret;
115
+ auth.connection.secret = args.options.secret || cli.getConfig().get(settingsNames.clientSecret);
92
116
  break;
93
117
  }
94
118
  auth.connection.cloudType = args.options.cloud;