@pnp/cli-microsoft365 7.10.0-beta.ebb7426 → 7.11.0-beta.10b9b79

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 (64) hide show
  1. package/.eslintrc.cjs +5 -2
  2. package/allCommands.json +1 -1
  3. package/allCommandsFull.json +1 -1
  4. package/dist/Auth.js +1 -1
  5. package/dist/AuthServer.js +10 -10
  6. package/dist/Command.js +10 -10
  7. package/dist/chili/index.js +1 -1
  8. package/dist/cli/cli.js +11 -11
  9. package/dist/index.js +1 -1
  10. package/dist/m365/base/AnonymousCommand.js +1 -1
  11. package/dist/m365/base/DelegatedGraphCommand.js +2 -2
  12. package/dist/m365/base/PowerAppsCommand.js +2 -2
  13. package/dist/m365/base/PowerAutomateCommand.js +2 -2
  14. package/dist/m365/base/PowerBICommand.js +2 -2
  15. package/dist/m365/base/PowerPlatformCommand.js +2 -2
  16. package/dist/m365/base/VivaEngageCommand.js +2 -2
  17. package/dist/m365/cli/commands/cli-consent.js +1 -1
  18. package/dist/m365/commands/login.js +1 -1
  19. package/dist/m365/commands/logout.js +1 -1
  20. package/dist/m365/commands/status.js +1 -1
  21. package/dist/m365/connection/commands/connection-list.js +1 -1
  22. package/dist/m365/connection/commands/connection-remove.js +1 -1
  23. package/dist/m365/connection/commands/connection-set.js +1 -1
  24. package/dist/m365/connection/commands/connection-use.js +1 -1
  25. package/dist/m365/entra/commands/app/app-permission-add.js +21 -1
  26. package/dist/m365/entra/commands/app/app-permission-remove.js +17 -0
  27. package/dist/m365/entra/commands/m365group/m365group-add.js +1 -0
  28. package/dist/m365/entra/commands/m365group/m365group-user-list.js +1 -1
  29. package/dist/m365/external/commands/connection/connection-doctor.js +1 -1
  30. package/dist/m365/external/commands/connection/connection-schema-add.js +4 -4
  31. package/dist/m365/file/commands/file-copy.js +3 -3
  32. package/dist/m365/pa/commands/app/app-export.js +1 -1
  33. package/dist/m365/pa/commands/app/app-owner-set.js +1 -1
  34. package/dist/m365/pp/commands/solution/solution-publish.js +1 -1
  35. package/dist/m365/purview/commands/threatassessment/threatassessment-list.js +1 -1
  36. package/dist/m365/spfx/commands/project/project-azuredevops-pipeline-add.js +1 -1
  37. package/dist/m365/spfx/commands/project/project-externalize.js +1 -1
  38. package/dist/m365/spfx/commands/project/project-github-workflow-add.js +1 -1
  39. package/dist/m365/spfx/commands/spfx-doctor.js +4 -4
  40. package/dist/m365/spo/commands/commandset/commandset-get.js +1 -1
  41. package/dist/m365/spo/commands/file/file-retentionlabel-remove.js +1 -1
  42. package/dist/m365/spo/commands/group/group-member-add.js +2 -2
  43. package/dist/m365/spo/commands/group/group-member-remove.js +2 -2
  44. package/dist/m365/spo/commands/list/list-retentionlabel-ensure.js +1 -1
  45. package/dist/m365/spo/commands/listitem/listitem-batch-remove.js +1 -1
  46. package/dist/m365/spo/commands/listitem/listitem-retentionlabel-ensure.js +2 -2
  47. package/dist/m365/spo/commands/listitem/listitem-retentionlabel-remove.js +2 -2
  48. package/dist/m365/spo/commands/site/site-admin-list.js +144 -0
  49. package/dist/m365/spo/commands/site/site-commsite-enable.js +1 -1
  50. package/dist/m365/spo/commands/spo-search.js +1 -1
  51. package/dist/m365/spo/commands/tenant/tenant-applicationcustomizer-set.js +4 -4
  52. package/dist/m365/spo/commands/tenant/tenant-commandset-set.js +2 -2
  53. package/dist/m365/spo/commands/user/user-ensure.js +1 -1
  54. package/dist/m365/spo/commands.js +1 -0
  55. package/dist/m365/teams/commands/chat/chat-member-add.js +1 -1
  56. package/dist/m365/teams/commands/meeting/meeting-list.js +1 -1
  57. package/dist/m365/viva/commands/engage/engage-community-get.js +1 -1
  58. package/dist/request.js +13 -14
  59. package/dist/utils/spo.js +5 -5
  60. package/dist/utils/validation.js +6 -0
  61. package/docs/docs/cmd/entra/app/app-permission-remove.mdx +4 -4
  62. package/docs/docs/cmd/spo/site/site-admin-list.mdx +115 -0
  63. package/npm-shrinkwrap.json +802 -601
  64. package/package.json +12 -12
@@ -60,7 +60,7 @@ class SpoCommandSetGetCommand extends SpoCommand {
60
60
  else {
61
61
  const resultAsKeyValuePair = formatting.convertArrayToHashTable('Id', commandSets);
62
62
  const commandSet = await cli.handleMultipleResultsFound(`Multiple command sets with title '${args.options.title}' found.`, resultAsKeyValuePair);
63
- logger.log(commandSet);
63
+ await logger.log(commandSet);
64
64
  }
65
65
  }
66
66
  }
@@ -54,7 +54,7 @@ class SpoFileRetentionLabelRemoveCommand extends SpoCommand {
54
54
  }
55
55
  async getFileProperties(logger, args) {
56
56
  if (this.verbose) {
57
- logger.logToStderr(`Retrieving list and item information for file '${args.options.fileId || args.options.fileUrl}' in site at ${args.options.webUrl}...`);
57
+ await logger.logToStderr(`Retrieving list and item information for file '${args.options.fileId || args.options.fileUrl}' in site at ${args.options.webUrl}...`);
58
58
  }
59
59
  let requestUrl = `${args.options.webUrl}/_api/web/`;
60
60
  if (args.options.fileId) {
@@ -34,11 +34,11 @@ class SpoGroupMemberAddCommand extends SpoCommand {
34
34
  try {
35
35
  if (args.options.aadGroupIds) {
36
36
  args.options.entraGroupIds = args.options.aadGroupIds;
37
- this.warn(logger, `Option 'aadGroupIds' is deprecated. Please use 'entraGroupIds' instead`);
37
+ await this.warn(logger, `Option 'aadGroupIds' is deprecated. Please use 'entraGroupIds' instead`);
38
38
  }
39
39
  if (args.options.aadGroupNames) {
40
40
  args.options.entraGroupNames = args.options.aadGroupNames;
41
- this.warn(logger, `Option 'aadGroupNames' is deprecated. Please use 'entraGroupNames' instead`);
41
+ await this.warn(logger, `Option 'aadGroupNames' is deprecated. Please use 'entraGroupNames' instead`);
42
42
  }
43
43
  const groupId = await this.getGroupId(args, logger);
44
44
  const resolvedUsernameList = await this.getValidUsers(args, logger);
@@ -47,11 +47,11 @@ class SpoGroupMemberRemoveCommand extends SpoCommand {
47
47
  async commandAction(logger, args) {
48
48
  if (args.options.aadGroupId) {
49
49
  args.options.entraGroupId = args.options.aadGroupId;
50
- this.warn(logger, `Option 'aadGroupId' is deprecated. Please use 'entraGroupId' instead`);
50
+ await this.warn(logger, `Option 'aadGroupId' is deprecated. Please use 'entraGroupId' instead`);
51
51
  }
52
52
  if (args.options.aadGroupName) {
53
53
  args.options.entraGroupName = args.options.aadGroupName;
54
- this.warn(logger, `Option 'aadGroupName' is deprecated. Please use 'entraGroupName' instead`);
54
+ await this.warn(logger, `Option 'aadGroupName' is deprecated. Please use 'entraGroupName' instead`);
55
55
  }
56
56
  if (args.options.force) {
57
57
  if (this.debug) {
@@ -38,7 +38,7 @@ class SpoListRetentionLabelEnsureCommand extends SpoCommand {
38
38
  }
39
39
  async getListServerRelativeUrl(args, logger) {
40
40
  if (this.verbose) {
41
- logger.logToStderr('Getting the list server relative URL');
41
+ await logger.logToStderr('Getting the list server relative URL');
42
42
  }
43
43
  if (args.options.listUrl) {
44
44
  return urlUtil.getServerRelativePath(args.options.webUrl, args.options.listUrl);
@@ -34,7 +34,7 @@ class SpoListItemBatchRemoveCommand extends SpoCommand {
34
34
  const removeListItems = async () => {
35
35
  try {
36
36
  if (this.verbose) {
37
- logger.logToStderr('Removing the listitems from SharePoint...');
37
+ await logger.logToStderr('Removing the listitems from SharePoint...');
38
38
  }
39
39
  let idsToRemove = [];
40
40
  if (args.options.filePath) {
@@ -46,7 +46,7 @@ class SpoListItemRetentionLabelEnsureCommand extends SpoCommand {
46
46
  return options.name;
47
47
  }
48
48
  if (this.verbose) {
49
- logger.logToStderr(`Retrieving the name of the retention label based on the Id '${options.id}'...`);
49
+ await logger.logToStderr(`Retrieving the name of the retention label based on the Id '${options.id}'...`);
50
50
  }
51
51
  const requestUrl = `${options.webUrl}/_api/SP.CompliancePolicy.SPPolicyStoreProxy.GetAvailableTagsForSite(siteUrl=@a1)?@a1='${formatting.encodeQueryParameter(options.webUrl)}'`;
52
52
  const labels = await odata.getAllItems(requestUrl);
@@ -87,7 +87,7 @@ class SpoListItemRetentionLabelEnsureCommand extends SpoCommand {
87
87
  const serverRelativePath = urlUtil.getServerRelativePath(options.webUrl, response.RootFolder.ServerRelativeUrl);
88
88
  const listAbsoluteUrl = urlUtil.urlCombine(tenantUrl, serverRelativePath);
89
89
  if (this.verbose) {
90
- logger.logToStderr(`List absolute URL found: '${listAbsoluteUrl}'`);
90
+ await logger.logToStderr(`List absolute URL found: '${listAbsoluteUrl}'`);
91
91
  }
92
92
  return listAbsoluteUrl;
93
93
  }
@@ -56,7 +56,7 @@ class SpoListItemRetentionLabelRemoveCommand extends SpoCommand {
56
56
  return urlUtil.urlCombine(tenantUrl, serverRelativePath);
57
57
  }
58
58
  if (this.verbose) {
59
- logger.logToStderr(`Retrieving list absolute URL...`);
59
+ await logger.logToStderr(`Retrieving list absolute URL...`);
60
60
  }
61
61
  let requestUrl = `${options.webUrl}/_api/web`;
62
62
  if (options.listId) {
@@ -76,7 +76,7 @@ class SpoListItemRetentionLabelRemoveCommand extends SpoCommand {
76
76
  const serverRelativePath = urlUtil.getServerRelativePath(options.webUrl, response.RootFolder.ServerRelativeUrl);
77
77
  const listAbsoluteUrl = urlUtil.urlCombine(tenantUrl, serverRelativePath);
78
78
  if (this.verbose) {
79
- logger.logToStderr(`List absolute URL found: '${listAbsoluteUrl}'`);
79
+ await logger.logToStderr(`List absolute URL found: '${listAbsoluteUrl}'`);
80
80
  }
81
81
  return listAbsoluteUrl;
82
82
  }
@@ -0,0 +1,144 @@
1
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
2
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
3
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
4
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
5
+ };
6
+ var _SpoSiteAdminListCommand_instances, _SpoSiteAdminListCommand_initTelemetry, _SpoSiteAdminListCommand_initOptions, _SpoSiteAdminListCommand_initValidators, _SpoSiteAdminListCommand_initTypes;
7
+ import request from '../../../../request.js';
8
+ import { spo } from '../../../../utils/spo.js';
9
+ import { validation } from '../../../../utils/validation.js';
10
+ import SpoCommand from '../../../base/SpoCommand.js';
11
+ import commands from '../../commands.js';
12
+ import { ListPrincipalType } from '../list/ListPrincipalType.js';
13
+ class SpoSiteAdminListCommand extends SpoCommand {
14
+ get name() {
15
+ return commands.SITE_ADMIN_LIST;
16
+ }
17
+ get description() {
18
+ return 'Lists all administrators of a specific SharePoint site';
19
+ }
20
+ constructor() {
21
+ super();
22
+ _SpoSiteAdminListCommand_instances.add(this);
23
+ __classPrivateFieldGet(this, _SpoSiteAdminListCommand_instances, "m", _SpoSiteAdminListCommand_initTelemetry).call(this);
24
+ __classPrivateFieldGet(this, _SpoSiteAdminListCommand_instances, "m", _SpoSiteAdminListCommand_initOptions).call(this);
25
+ __classPrivateFieldGet(this, _SpoSiteAdminListCommand_instances, "m", _SpoSiteAdminListCommand_initValidators).call(this);
26
+ __classPrivateFieldGet(this, _SpoSiteAdminListCommand_instances, "m", _SpoSiteAdminListCommand_initTypes).call(this);
27
+ }
28
+ async commandAction(logger, args) {
29
+ try {
30
+ if (args.options.asAdmin) {
31
+ await this.callActionAsAdmin(logger, args);
32
+ return;
33
+ }
34
+ await this.callAction(logger, args);
35
+ }
36
+ catch (err) {
37
+ this.handleRejectedODataJsonPromise(err);
38
+ }
39
+ }
40
+ async callActionAsAdmin(logger, args) {
41
+ if (this.verbose) {
42
+ await logger.logToStderr('Retrieving site administrators as an administrator...');
43
+ }
44
+ const adminUrl = await spo.getSpoAdminUrl(logger, this.debug);
45
+ const siteId = await this.getSiteId(args.options.siteUrl, logger);
46
+ const requestOptions = {
47
+ url: `${adminUrl}/_api/SPO.Tenant/GetSiteAdministrators?siteId='${siteId}'`,
48
+ headers: {
49
+ accept: 'application/json;odata=nometadata',
50
+ 'content-type': 'application/json;charset=utf-8'
51
+ }
52
+ };
53
+ const response = await request.post(requestOptions);
54
+ const responseContent = JSON.parse(response);
55
+ const primaryAdminLoginName = await this.getPrimaryAdminLoginNameFromAdmin(adminUrl, siteId);
56
+ const mappedResult = responseContent.value.map((u) => ({
57
+ Id: null,
58
+ Email: u.email,
59
+ LoginName: u.loginName,
60
+ Title: u.name,
61
+ PrincipalType: null,
62
+ PrincipalTypeString: null,
63
+ IsPrimaryAdmin: u.loginName === primaryAdminLoginName
64
+ }));
65
+ await logger.log(mappedResult);
66
+ }
67
+ async getSiteId(siteUrl, logger) {
68
+ const siteGraphId = await spo.getSiteId(siteUrl, logger, this.verbose);
69
+ const match = siteGraphId.match(/,([a-f0-9\-]{36}),/i);
70
+ if (!match) {
71
+ throw `Site with URL ${siteUrl} not found`;
72
+ }
73
+ return match[1];
74
+ }
75
+ async getPrimaryAdminLoginNameFromAdmin(adminUrl, siteId) {
76
+ const requestOptions = {
77
+ url: `${adminUrl}/_api/SPO.Tenant/sites('${siteId}')?$select=OwnerLoginName`,
78
+ headers: {
79
+ accept: 'application/json;odata=nometadata',
80
+ 'content-type': 'application/json;charset=utf-8'
81
+ }
82
+ };
83
+ const response = await request.get(requestOptions);
84
+ const responseContent = JSON.parse(response);
85
+ return responseContent.OwnerLoginName;
86
+ }
87
+ async callAction(logger, args) {
88
+ if (this.verbose) {
89
+ await logger.logToStderr('Retrieving site administrators...');
90
+ }
91
+ const requestOptions = {
92
+ url: `${args.options.siteUrl}/_api/web/siteusers?$filter=IsSiteAdmin eq true`,
93
+ method: 'GET',
94
+ headers: {
95
+ 'accept': 'application/json;odata=nometadata'
96
+ },
97
+ responseType: 'json'
98
+ };
99
+ const responseContent = await request.get(requestOptions);
100
+ const primaryOwnerLogin = await this.getPrimaryOwnerLoginFromSite(args.options.siteUrl);
101
+ const mappedResult = responseContent.value.map((u) => ({
102
+ Id: u.Id,
103
+ LoginName: u.LoginName,
104
+ Title: u.Title,
105
+ PrincipalType: u.PrincipalType,
106
+ PrincipalTypeString: ListPrincipalType[u.PrincipalType],
107
+ Email: u.Email,
108
+ IsPrimaryAdmin: u.LoginName === primaryOwnerLogin
109
+ }));
110
+ await logger.log(mappedResult);
111
+ }
112
+ async getPrimaryOwnerLoginFromSite(siteUrl) {
113
+ const requestOptions = {
114
+ url: `${siteUrl}/_api/site/owner`,
115
+ method: 'GET',
116
+ headers: {
117
+ 'accept': 'application/json;odata=nometadata'
118
+ },
119
+ responseType: 'json'
120
+ };
121
+ const responseContent = await request.get(requestOptions);
122
+ return responseContent?.LoginName ?? null;
123
+ }
124
+ }
125
+ _SpoSiteAdminListCommand_instances = new WeakSet(), _SpoSiteAdminListCommand_initTelemetry = function _SpoSiteAdminListCommand_initTelemetry() {
126
+ this.telemetry.push((args) => {
127
+ Object.assign(this.telemetryProperties, {
128
+ siteUrl: typeof args.options.siteUrl !== 'undefined',
129
+ asAdmin: !!args.options.asAdmin
130
+ });
131
+ });
132
+ }, _SpoSiteAdminListCommand_initOptions = function _SpoSiteAdminListCommand_initOptions() {
133
+ this.options.unshift({
134
+ option: '-u, --siteUrl <siteUrl>'
135
+ }, {
136
+ option: '--asAdmin'
137
+ });
138
+ }, _SpoSiteAdminListCommand_initValidators = function _SpoSiteAdminListCommand_initValidators() {
139
+ this.validators.push(async (args) => validation.isValidSharePointUrl(args.options.siteUrl));
140
+ }, _SpoSiteAdminListCommand_initTypes = function _SpoSiteAdminListCommand_initTypes() {
141
+ this.types.string.push('siteUrl');
142
+ };
143
+ export default new SpoSiteAdminListCommand();
144
+ //# sourceMappingURL=site-admin-list.js.map
@@ -26,7 +26,7 @@ class SpoSiteCommSiteEnableCommand extends SpoCommand {
26
26
  async commandAction(logger, args) {
27
27
  const designPackageId = this.getDesignPackageId(args.options);
28
28
  if (this.verbose) {
29
- logger.logToStderr(`Enabling communication site with design package '${designPackageId}' at '${args.options.url}'...`);
29
+ await logger.logToStderr(`Enabling communication site with design package '${designPackageId}' at '${args.options.url}'...`);
30
30
  }
31
31
  try {
32
32
  const requestOptions = {
@@ -39,7 +39,7 @@ class SpoSearchCommand extends SpoCommand {
39
39
  await logger.logToStderr(`Executing search query '${args.options.queryText}' on site at ${webUrl}...`);
40
40
  }
41
41
  const results = await this.executeSearchQuery(logger, args, webUrl, []);
42
- this.printResults(logger, args, results);
42
+ await this.printResults(logger, args, results);
43
43
  }
44
44
  catch (err) {
45
45
  this.handleRejectedODataJsonPromise(err);
@@ -76,7 +76,7 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand {
76
76
  }
77
77
  async getComponentManifest(appCatalogUrl, clientSideComponentId, logger) {
78
78
  if (this.verbose) {
79
- logger.logToStderr('Retrieving component manifest item from the ComponentManifests list on the app catalog site so that we get the solution id');
79
+ await logger.logToStderr('Retrieving component manifest item from the ComponentManifests list on the app catalog site so that we get the solution id');
80
80
  }
81
81
  const camlQuery = `<View><ViewFields><FieldRef Name='ClientComponentId'></FieldRef><FieldRef Name='SolutionId'></FieldRef><FieldRef Name='ClientComponentManifest'></FieldRef></ViewFields><Query><Where><Eq><FieldRef Name='ClientComponentId' /><Value Type='Guid'>${clientSideComponentId}</Value></Eq></Where></Query></View>`;
82
82
  const commandOptions = {
@@ -89,7 +89,7 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand {
89
89
  };
90
90
  const output = await cli.executeCommandWithOutput(spoListItemListCommand, { options: { ...commandOptions, _: [] } });
91
91
  if (this.verbose) {
92
- logger.logToStderr(output.stderr);
92
+ await logger.logToStderr(output.stderr);
93
93
  }
94
94
  const outputParsed = JSON.parse(output.stdout);
95
95
  if (outputParsed.length === 0) {
@@ -99,7 +99,7 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand {
99
99
  }
100
100
  async getSolutionFromAppCatalog(appCatalogUrl, solutionId, logger) {
101
101
  if (this.verbose) {
102
- logger.logToStderr(`Retrieving solution with id ${solutionId} from the application catalog`);
102
+ await logger.logToStderr(`Retrieving solution with id ${solutionId} from the application catalog`);
103
103
  }
104
104
  const camlQuery = `<View><ViewFields><FieldRef Name='SkipFeatureDeployment'></FieldRef><FieldRef Name='ContainsTenantWideExtension'></FieldRef></ViewFields><Query><Where><Eq><FieldRef Name='AppProductID' /><Value Type='Guid'>${solutionId}</Value></Eq></Where></Query></View>`;
105
105
  const commandOptions = {
@@ -112,7 +112,7 @@ class SpoTenantApplicationCustomizerSetCommand extends SpoCommand {
112
112
  };
113
113
  const output = await cli.executeCommandWithOutput(spoListItemListCommand, { options: { ...commandOptions, _: [] } });
114
114
  if (this.verbose) {
115
- logger.logToStderr(output.stderr);
115
+ await logger.logToStderr(output.stderr);
116
116
  }
117
117
  const outputParsed = JSON.parse(output.stdout);
118
118
  if (outputParsed.length === 0) {
@@ -44,7 +44,7 @@ class SpoTenantCommandSetSetCommand extends SpoCommand {
44
44
  }
45
45
  async getListItemById(logger, webUrl, listServerRelativeUrl, id) {
46
46
  if (this.verbose) {
47
- logger.logToStderr(`Getting the list item by id ${id}`);
47
+ await logger.logToStderr(`Getting the list item by id ${id}`);
48
48
  }
49
49
  const reqOptions = {
50
50
  url: `${webUrl}/_api/web/GetList('${formatting.encodeQueryParameter(listServerRelativeUrl)}')/Items(${id})`,
@@ -57,7 +57,7 @@ class SpoTenantCommandSetSetCommand extends SpoCommand {
57
57
  }
58
58
  async updateTenantWideExtension(appCatalogUrl, options, listServerRelativeUrl, logger) {
59
59
  if (this.verbose) {
60
- logger.logToStderr('Updating tenant wide extension to the TenantWideExtensions list');
60
+ await logger.logToStderr('Updating tenant wide extension to the TenantWideExtensions list');
61
61
  }
62
62
  const formValues = [];
63
63
  if (options.newTitle !== undefined) {
@@ -27,7 +27,7 @@ class SpoUserEnsureCommand extends SpoCommand {
27
27
  async commandAction(logger, args) {
28
28
  if (args.options.aadId) {
29
29
  args.options.entraId = args.options.aadId;
30
- this.warn(logger, `Option 'aadId' is deprecated. Please use 'entraId' instead`);
30
+ await this.warn(logger, `Option 'aadId' is deprecated. Please use 'entraId' instead`);
31
31
  }
32
32
  if (this.verbose) {
33
33
  await logger.logToStderr(`Ensuring user ${args.options.entraId || args.options.userName} at site ${args.options.webUrl}`);
@@ -239,6 +239,7 @@ export default {
239
239
  SERVICEPRINCIPAL_SET: `${prefix} serviceprincipal set`,
240
240
  SET: `${prefix} set`,
241
241
  SITE_ADD: `${prefix} site add`,
242
+ SITE_ADMIN_LIST: `${prefix} site admin list`,
242
243
  SITE_APPCATALOG_ADD: `${prefix} site appcatalog add`,
243
244
  SITE_APPCATALOG_LIST: `${prefix} site appcatalog list`,
244
245
  SITE_APPCATALOG_REMOVE: `${prefix} site appcatalog remove`,
@@ -27,7 +27,7 @@ class TeamsChatMemberAddCommand extends GraphCommand {
27
27
  async commandAction(logger, args) {
28
28
  try {
29
29
  if (this.verbose) {
30
- logger.logToStderr(`Adding member ${args.options.userId || args.options.userName} to chat with id ${args.options.chatId}...`);
30
+ await logger.logToStderr(`Adding member ${args.options.userId || args.options.userName} to chat with id ${args.options.chatId}...`);
31
31
  }
32
32
  const chatMemberAddOptions = {
33
33
  url: `${this.resource}/v1.0/chats/${args.options.chatId}/members`,
@@ -90,7 +90,7 @@ class TeamsMeetingListCommand extends GraphCommand {
90
90
  let result = [];
91
91
  for (let i = 0; i < meetingUrls.length; i += 20) {
92
92
  if (this.verbose) {
93
- logger.logToStderr(`Retrieving meetings ${i + 1}-${Math.min(i + 20, meetingUrls.length)}...`);
93
+ await logger.logToStderr(`Retrieving meetings ${i + 1}-${Math.min(i + 20, meetingUrls.length)}...`);
94
94
  }
95
95
  const batch = meetingUrls.slice(i, i + 20);
96
96
  const requestOptions = {
@@ -22,7 +22,7 @@ class VivaEngageCommunityGetCommand extends GraphCommand {
22
22
  }
23
23
  async commandAction(logger, args) {
24
24
  if (this.verbose) {
25
- logger.logToStderr(`Getting the information of Viva Engage community with id '${args.options.id}'...`);
25
+ await logger.logToStderr(`Getting the information of Viva Engage community with id '${args.options.id}'...`);
26
26
  }
27
27
  const requestOptions = {
28
28
  url: `${this.resource}/beta/employeeExperience/communities/${args.options.id}`,
package/dist/request.js CHANGED
@@ -14,39 +14,39 @@ class Request {
14
14
  }
15
15
  this._debug = debug;
16
16
  if (this._debug) {
17
- this.req.interceptors.request.use(config => {
17
+ this.req.interceptors.request.use(async (config) => {
18
18
  if (this._logger) {
19
- this._logger.logToStderr('Request:');
19
+ await this._logger.logToStderr('Request:');
20
20
  const properties = ['url', 'method', 'headers', 'responseType', 'decompress'];
21
21
  if (config.responseType !== 'stream') {
22
22
  properties.push('data');
23
23
  }
24
- this._logger.logToStderr(JSON.stringify(formatting.filterObject(config, properties), null, 2));
24
+ await this._logger.logToStderr(JSON.stringify(formatting.filterObject(config, properties), null, 2));
25
25
  }
26
26
  return config;
27
27
  });
28
28
  // since we're stubbing requests, response interceptor is never called in
29
29
  // tests, so let's exclude it from coverage
30
30
  /* c8 ignore next 26 */
31
- this.req.interceptors.response.use((response) => {
31
+ this.req.interceptors.response.use(async (response) => {
32
32
  if (this._logger) {
33
- this._logger.logToStderr('Response:');
33
+ await this._logger.logToStderr('Response:');
34
34
  const properties = ['status', 'statusText', 'headers'];
35
35
  if (response.headers['content-type'] &&
36
36
  response.headers['content-type'].indexOf('json') > -1) {
37
37
  properties.push('data');
38
38
  }
39
- this._logger.logToStderr(JSON.stringify({
39
+ await this._logger.logToStderr(JSON.stringify({
40
40
  url: response.config.url,
41
41
  ...formatting.filterObject(response, properties)
42
42
  }, null, 2));
43
43
  }
44
44
  return response;
45
- }, (error) => {
45
+ }, async (error) => {
46
46
  if (this._logger) {
47
47
  const properties = ['status', 'statusText', 'headers'];
48
- this._logger.logToStderr('Request error:');
49
- this._logger.logToStderr(JSON.stringify({
48
+ await this._logger.logToStderr('Request error:');
49
+ await this._logger.logToStderr(JSON.stringify({
50
50
  url: error.config?.url,
51
51
  ...formatting.filterObject(error.response, properties),
52
52
  error: error.error
@@ -169,7 +169,7 @@ class Request {
169
169
  timings.api.push(Number(end - start));
170
170
  _resolve((options.responseType === 'stream' || options.fullResponse) ? res : res.data);
171
171
  }
172
- }, (error) => {
172
+ }, async (error) => {
173
173
  if (error && error.response &&
174
174
  (error.response.status === 429 ||
175
175
  error.response.status === 503)) {
@@ -178,11 +178,10 @@ class Request {
178
178
  retryAfter = 10;
179
179
  }
180
180
  if (this._debug) {
181
- this._logger.log(`Request throttled. Waiting ${retryAfter}sec before retrying...`);
181
+ await this._logger.log(`Request throttled. Waiting ${retryAfter}sec before retrying...`);
182
182
  }
183
- setTimeout(() => {
184
- this.execute(options, resolve || _resolve, reject || _reject);
185
- }, retryAfter * 1000);
183
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
184
+ setTimeout(async () => { this.execute(options, resolve || _resolve, reject || _reject); }, retryAfter * 1000);
186
185
  }
187
186
  else {
188
187
  if (reject) {
package/dist/utils/spo.js CHANGED
@@ -1173,7 +1173,7 @@ export const spo = {
1173
1173
  */
1174
1174
  async getFileAsListItemByUrl(absoluteListUrl, url, logger, verbose) {
1175
1175
  if (verbose && logger) {
1176
- logger.logToStderr(`Getting the file properties with url ${url}`);
1176
+ await logger.logToStderr(`Getting the file properties with url ${url}`);
1177
1177
  }
1178
1178
  const serverRelativePath = urlUtil.getServerRelativePath(absoluteListUrl, url);
1179
1179
  const requestUrl = `${absoluteListUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl=@f)?$expand=ListItemAllFields&@f='${formatting.encodeQueryParameter(serverRelativePath)}'`;
@@ -1206,7 +1206,7 @@ export const spo = {
1206
1206
  const serverRelativeSiteMatch = absoluteListUrl.match(new RegExp('/sites/[^/]+'));
1207
1207
  const webUrl = `${parsedUrl.protocol}//${parsedUrl.host}${serverRelativeSiteMatch ?? ''}`;
1208
1208
  if (verbose && logger) {
1209
- logger.logToStderr(`Getting list id...`);
1209
+ await logger.logToStderr(`Getting list id...`);
1210
1210
  }
1211
1211
  const listRequestOptions = {
1212
1212
  url: `${absoluteListUrl}?$select=Id`,
@@ -1218,7 +1218,7 @@ export const spo = {
1218
1218
  const list = await request.get(listRequestOptions);
1219
1219
  const listId = list.Id;
1220
1220
  if (verbose && logger) {
1221
- logger.logToStderr(`Getting request digest for systemUpdate request`);
1221
+ await logger.logToStderr(`Getting request digest for systemUpdate request`);
1222
1222
  }
1223
1223
  const res = await spo.getRequestDigest(webUrl);
1224
1224
  const formDigestValue = res.FormDigestValue;
@@ -1361,7 +1361,7 @@ export const spo = {
1361
1361
  */
1362
1362
  async getSiteId(webUrl, logger, verbose) {
1363
1363
  if (verbose && logger) {
1364
- logger.logToStderr(`Getting site id for URL: ${webUrl}...`);
1364
+ await logger.logToStderr(`Getting site id for URL: ${webUrl}...`);
1365
1365
  }
1366
1366
  const url = new URL(webUrl);
1367
1367
  const requestOptions = {
@@ -1393,7 +1393,7 @@ export const spo = {
1393
1393
  };
1394
1394
  const response = await request.post(requestOptions);
1395
1395
  if (verbose) {
1396
- logger.logToStderr('Attempt to get _ObjectIdentity_ key values');
1396
+ await logger.logToStderr('Attempt to get _ObjectIdentity_ key values');
1397
1397
  }
1398
1398
  const json = JSON.parse(response);
1399
1399
  const contents = json.find(x => { return x.ErrorInfo; });
@@ -332,6 +332,12 @@ export const validation = {
332
332
  isValidISODuration(duration) {
333
333
  const durationRegEx = new RegExp(/^P(?!$)((\d+Y)|(\d+\.\d+Y$))?((\d+M)|(\d+\.\d+M$))?((\d+W)|(\d+\.\d+W$))?((\d+D)|(\d+\.\d+D$))?(T(?=\d)((\d+H)|(\d+\.\d+H$))?((\d+M)|(\d+\.\d+M$))?(\d+(\.\d+)?S)?)??$/);
334
334
  return durationRegEx.test(duration);
335
+ },
336
+ isValidPermission(permissions) {
337
+ const invalidPermissions = permissions
338
+ .split(' ')
339
+ .filter(permission => permission.indexOf('/') < 0);
340
+ return invalidPermissions.length > 0 ? invalidPermissions : true;
335
341
  }
336
342
  };
337
343
  //# sourceMappingURL=validation.js.map
@@ -14,19 +14,19 @@ m365 entra app permission remove [options]
14
14
 
15
15
  ```md definition-list
16
16
  `-i, --appId [appId]`
17
- : Client ID of the Microsoft Entra app to add the API permissions to. Specify either `appId`, `appName` or `appObjectId`.
17
+ : Client ID of the Microsoft Entra app to remove the API permissions from. Specify either `appId`, `appName` or `appObjectId`.
18
18
 
19
19
  `--appObjectId [appObjectId]`
20
- : Object ID of the Microsoft Entra app to add the API permissions to. Specify either `appId`, `appName` or `appObjectId`.
20
+ : Object ID of the Microsoft Entra app to remove the API permissions from. Specify either `appId`, `appName` or `appObjectId`.
21
21
 
22
22
  `-n, --appName [appName]`
23
23
  : Display name of the Entra app to remove the API permissions from. Specify either `appId`, `appName` or `appObjectId`.
24
24
 
25
25
  `-a, --applicationPermissions [applicationPermissions]`
26
- : Space-separated list of application permissions to add. Specify at least `applicationPermissions` or `delegatedPermissions`.
26
+ : Space-separated list of application permissions to remove. Specify at least `applicationPermissions` or `delegatedPermissions`.
27
27
 
28
28
  `-d, --delegatedPermissions [delegatedPermissions]`
29
- : Space-separated list of delegated permissions to add. Specify at least `applicationPermissions` or `delegatedPermissions`.
29
+ : Space-separated list of delegated permissions to remove. Specify at least `applicationPermissions` or `delegatedPermissions`.
30
30
 
31
31
  `--revokeAdminConsent`
32
32
  : When specified, revokes the admin consent for the specified permissions as well.
@@ -0,0 +1,115 @@
1
+ import Global from '/docs/cmd/_global.mdx';
2
+ import Tabs from '@theme/Tabs';
3
+ import TabItem from '@theme/TabItem';
4
+
5
+ # spo site admin list
6
+
7
+ Lists all administrators of a specific SharePoint site
8
+
9
+ ## Usage
10
+
11
+ ```sh
12
+ m365 spo site admin list [options]
13
+ ```
14
+
15
+ ## Options
16
+
17
+ ```md definition-list
18
+ `-u, --siteUrl <siteUrl>`
19
+ : The URL of the SharePoint site
20
+
21
+ `--asAdmin`
22
+ : List admins as admin for sites you don't have permission to
23
+ ```
24
+
25
+ <Global />
26
+
27
+ ## Remarks
28
+
29
+ :::info
30
+
31
+ To use this command with the `--asAdmin` mode, you must have permission to access the tenant admin site.
32
+
33
+ Without this parameter, you must have site collection admin permissions for the requested site.
34
+
35
+ In `--asAdmin` mode, the Id, PrincipalType, and PrincipalTypeString properties are not exported.
36
+
37
+ :::
38
+
39
+ ## Examples
40
+
41
+ Lists all admins of a SharePoint site
42
+
43
+ ```sh
44
+ m365 spo site admin list --siteUrl https://contoso.sharepoint.com
45
+ ```
46
+
47
+ Lists all admins of a SharePoint site as admin
48
+
49
+ ```sh
50
+ m365 spo site admin list --siteUrl https://contoso.sharepoint.com --asAdmin
51
+ ```
52
+
53
+ ## Response
54
+
55
+ <Tabs>
56
+ <TabItem value="JSON">
57
+
58
+ ```json
59
+ [
60
+ {
61
+ "Id": 6,
62
+ "LoginName": "i:0#.f|membership|user@contoso.com",
63
+ "Title": "User Example",
64
+ "PrincipalType": 1,
65
+ "PrincipalTypeString": "User",
66
+ "Email": "user@contoso.com",
67
+ "IsPrimaryAdmin": true
68
+ }
69
+ ]
70
+ ```
71
+
72
+ </TabItem>
73
+ <TabItem value="Text">
74
+
75
+ ```text
76
+ Email : user@contoso.com
77
+ Id : 6
78
+ LoginName : i:0#.f|membership|user@contoso.com
79
+ PrincipalType : 1
80
+ PrincipalTypeString : User
81
+ Title : User Example
82
+ IsPrimaryAdmin : true
83
+ ```
84
+
85
+ </TabItem>
86
+ <TabItem value="CSV">
87
+
88
+ ```csv
89
+ Id,LoginName,Title,PrincipalType,PrincipalTypeString,Email,IsPrimaryAdmin
90
+ 6,i:0#.f|membership|user@contoso.com,User Example,1,User,user@contoso.com,1
91
+ ```
92
+
93
+ </TabItem>
94
+ <TabItem value="Markdown">
95
+
96
+ ```md
97
+ # spo site admin list --siteUrl "https://contoso.sharepoint.com/sites/Test"
98
+
99
+ Date: 20/03/2024
100
+
101
+ ## User
102
+
103
+ Property | Value
104
+ ---------|-------
105
+ Id | 6
106
+ LoginName | i:0#.f\|membership\|user@contoso.com
107
+ Title | User Example
108
+ PrincipalType | 1
109
+ PrincipalTypeString | User
110
+ Email | user@contoso.com
111
+ IsPrimaryAdmin | true
112
+ ```
113
+
114
+ </TabItem>
115
+ </Tabs>