@pnp/cli-microsoft365 10.4.0 → 10.5.0-beta.31bfdff

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.
@@ -0,0 +1,85 @@
1
+ import { z } from 'zod';
2
+ import { globalOptionsZod } from '../../../../Command.js';
3
+ import request from '../../../../request.js';
4
+ import { zod } from '../../../../utils/zod.js';
5
+ import commands from '../../commands.js';
6
+ import GraphCommand from '../../../base/GraphCommand.js';
7
+ import { validation } from '../../../../utils/validation.js';
8
+ import { entraApp } from '../../../../utils/entraApp.js';
9
+ const options = globalOptionsZod
10
+ .extend({
11
+ name: zod.alias('n', z.string()),
12
+ appId: z.string().optional(),
13
+ appObjectId: z.string().optional(),
14
+ appName: z.string().optional(),
15
+ dataType: z.enum(['Binary', 'Boolean', 'DateTime', 'Integer', 'LargeInteger', 'String']),
16
+ targetObjects: z.string().transform((value) => value.split(',').map(String))
17
+ .pipe(z.enum(['User', 'Group', 'Application', 'AdministrativeUnit', 'Device', 'Organization']).array()),
18
+ isMultiValued: z.boolean().optional()
19
+ })
20
+ .strict();
21
+ class GraphDirectoryExtensionAddCommand extends GraphCommand {
22
+ get name() {
23
+ return commands.DIRECTORYEXTENSION_ADD;
24
+ }
25
+ get description() {
26
+ return 'Creates a new directory extension';
27
+ }
28
+ get schema() {
29
+ return options;
30
+ }
31
+ getRefinedSchema(schema) {
32
+ return schema
33
+ .refine(options => Object.values([options.appId, options.appObjectId, options.appName]).filter(v => typeof v !== 'undefined').length === 1, {
34
+ message: 'Specify either appId, appObjectId or appName, but not multiple'
35
+ })
36
+ .refine(options => (!options.appId && !options.appObjectId && !options.appName) || options.appObjectId || options.appName ||
37
+ (options.appId && validation.isValidGuid(options.appId)), options => ({
38
+ message: `The '${options.appId}' must be a valid GUID`,
39
+ path: ['appId']
40
+ }))
41
+ .refine(options => (!options.appId && !options.appObjectId && !options.appName) || options.appId || options.appName ||
42
+ (options.appObjectId && validation.isValidGuid(options.appObjectId)), options => ({
43
+ message: `The '${options.appObjectId}' must be a valid GUID`,
44
+ path: ['appObjectId']
45
+ }));
46
+ }
47
+ async commandAction(logger, args) {
48
+ try {
49
+ const appObjectId = await this.getAppObjectId(args.options);
50
+ if (args.options.verbose) {
51
+ await logger.logToStderr(`Adding directory extension to the app with id '${appObjectId}'...`);
52
+ }
53
+ const requestOptions = {
54
+ url: `${this.resource}/v1.0/applications/${appObjectId}/extensionProperties`,
55
+ headers: {
56
+ accept: 'application/json;odata.metadata=none',
57
+ 'content-type': 'application/json'
58
+ },
59
+ data: {
60
+ name: args.options.name,
61
+ dataType: args.options.dataType,
62
+ targetObjects: args.options.targetObjects,
63
+ isMultiValued: args.options.isMultiValued
64
+ },
65
+ responseType: 'json'
66
+ };
67
+ const res = await request.post(requestOptions);
68
+ await logger.log(res);
69
+ }
70
+ catch (err) {
71
+ this.handleRejectedODataJsonPromise(err);
72
+ }
73
+ }
74
+ async getAppObjectId(options) {
75
+ if (options.appObjectId) {
76
+ return options.appObjectId;
77
+ }
78
+ if (options.appId) {
79
+ return (await entraApp.getAppRegistrationByAppId(options.appId, ["id"])).id;
80
+ }
81
+ return (await entraApp.getAppRegistrationByAppName(options.appName, ["id"])).id;
82
+ }
83
+ }
84
+ export default new GraphDirectoryExtensionAddCommand();
85
+ //# sourceMappingURL=directoryextension-add.js.map
@@ -0,0 +1,82 @@
1
+ import { z } from 'zod';
2
+ import { globalOptionsZod } from '../../../../Command.js';
3
+ import request from '../../../../request.js';
4
+ import { zod } from '../../../../utils/zod.js';
5
+ import commands from '../../commands.js';
6
+ import GraphCommand from '../../../base/GraphCommand.js';
7
+ import { validation } from '../../../../utils/validation.js';
8
+ import { entraApp } from '../../../../utils/entraApp.js';
9
+ import { directoryExtension } from '../../../../utils/directoryExtension.js';
10
+ const options = globalOptionsZod
11
+ .extend({
12
+ id: zod.alias('i', z.string().refine(id => validation.isValidGuid(id), id => ({
13
+ message: `'${id}' is not a valid GUID.`
14
+ })).optional()),
15
+ name: zod.alias('n', z.string().optional()),
16
+ appId: z.string().refine(id => validation.isValidGuid(id), id => ({
17
+ message: `'${id}' is not a valid GUID.`
18
+ })).optional(),
19
+ appObjectId: z.string().refine(id => validation.isValidGuid(id), id => ({
20
+ message: `'${id}' is not a valid GUID.`
21
+ })).optional(),
22
+ appName: z.string().optional()
23
+ })
24
+ .strict();
25
+ class GraphDirectoryExtensionGetCommand extends GraphCommand {
26
+ get name() {
27
+ return commands.DIRECTORYEXTENSION_GET;
28
+ }
29
+ get description() {
30
+ return 'Retrieves the definition of a directory extension';
31
+ }
32
+ get schema() {
33
+ return options;
34
+ }
35
+ getRefinedSchema(schema) {
36
+ return schema
37
+ .refine(options => !options.id !== !options.name, {
38
+ message: 'Specify either id or name, but not both'
39
+ })
40
+ .refine(options => options.id || options.name, {
41
+ message: 'Specify either id or name'
42
+ })
43
+ .refine(options => Object.values([options.appId, options.appObjectId, options.appName]).filter(v => typeof v !== 'undefined').length === 1, {
44
+ message: 'Specify either appId, appObjectId or appName, but not multiple'
45
+ });
46
+ }
47
+ async commandAction(logger, args) {
48
+ try {
49
+ const appObjectId = await this.getAppObjectId(args.options);
50
+ let schemeExtensionId = args.options.id;
51
+ if (args.options.name) {
52
+ schemeExtensionId = (await directoryExtension.getDirectoryExtensionByName(args.options.name, appObjectId, ['id'])).id;
53
+ }
54
+ if (args.options.verbose) {
55
+ await logger.logToStderr(`Retrieving schema extension with ID ${schemeExtensionId} from application with ID ${appObjectId}...`);
56
+ }
57
+ const requestOptions = {
58
+ url: `${this.resource}/v1.0/applications/${appObjectId}/extensionProperties/${schemeExtensionId}`,
59
+ headers: {
60
+ accept: 'application/json;odata.metadata=none'
61
+ },
62
+ responseType: 'json'
63
+ };
64
+ const res = await request.get(requestOptions);
65
+ await logger.log(res);
66
+ }
67
+ catch (err) {
68
+ this.handleRejectedODataJsonPromise(err);
69
+ }
70
+ }
71
+ async getAppObjectId(options) {
72
+ if (options.appObjectId) {
73
+ return options.appObjectId;
74
+ }
75
+ if (options.appId) {
76
+ return (await entraApp.getAppRegistrationByAppId(options.appId, ["id"])).id;
77
+ }
78
+ return (await entraApp.getAppRegistrationByAppName(options.appName, ["id"])).id;
79
+ }
80
+ }
81
+ export default new GraphDirectoryExtensionGetCommand();
82
+ //# sourceMappingURL=directoryextension-get.js.map
@@ -0,0 +1,93 @@
1
+ import { z } from 'zod';
2
+ import { globalOptionsZod } from '../../../../Command.js';
3
+ import request from '../../../../request.js';
4
+ import { zod } from '../../../../utils/zod.js';
5
+ import commands from '../../commands.js';
6
+ import GraphCommand from '../../../base/GraphCommand.js';
7
+ import { validation } from '../../../../utils/validation.js';
8
+ import { entraApp } from '../../../../utils/entraApp.js';
9
+ import { cli } from '../../../../cli/cli.js';
10
+ import { directoryExtension } from '../../../../utils/directoryExtension.js';
11
+ const options = globalOptionsZod
12
+ .extend({
13
+ id: zod.alias('i', z.string().refine(id => validation.isValidGuid(id), id => ({
14
+ message: `'${id}' is not a valid GUID.`
15
+ })).optional()),
16
+ name: zod.alias('n', z.string().optional()),
17
+ appId: z.string().refine(id => validation.isValidGuid(id), id => ({
18
+ message: `'${id}' is not a valid GUID.`
19
+ })).optional(),
20
+ appObjectId: z.string().refine(id => validation.isValidGuid(id), id => ({
21
+ message: `'${id}' is not a valid GUID.`
22
+ })).optional(),
23
+ appName: z.string().optional(),
24
+ force: zod.alias('f', z.boolean().optional())
25
+ })
26
+ .strict();
27
+ class GraphDirectoryExtensionRemoveCommand extends GraphCommand {
28
+ get name() {
29
+ return commands.DIRECTORYEXTENSION_REMOVE;
30
+ }
31
+ get description() {
32
+ return 'Removes a directory extension';
33
+ }
34
+ get schema() {
35
+ return options;
36
+ }
37
+ getRefinedSchema(schema) {
38
+ return schema
39
+ .refine(options => !options.id !== !options.name, {
40
+ message: 'Specify either id or name, but not both'
41
+ })
42
+ .refine(options => options.id || options.name, {
43
+ message: 'Specify either id or name'
44
+ })
45
+ .refine(options => Object.values([options.appId, options.appObjectId, options.appName]).filter(v => typeof v !== 'undefined').length === 1, {
46
+ message: 'Specify either appId, appObjectId or appName, but not multiple'
47
+ });
48
+ }
49
+ async commandAction(logger, args) {
50
+ const removeDirectoryExtension = async () => {
51
+ try {
52
+ const appObjectId = await this.getAppObjectId(args.options);
53
+ let schemeExtensionId = args.options.id;
54
+ if (args.options.name) {
55
+ schemeExtensionId = (await directoryExtension.getDirectoryExtensionByName(args.options.name, appObjectId, ['id'])).id;
56
+ }
57
+ if (args.options.verbose) {
58
+ await logger.logToStderr(`Removing schema extension with ID ${schemeExtensionId} from application with ID ${appObjectId}...`);
59
+ }
60
+ const requestOptions = {
61
+ url: `${this.resource}/v1.0/applications/${appObjectId}/extensionProperties/${schemeExtensionId}`,
62
+ headers: {
63
+ accept: 'application/json;odata.metadata=none'
64
+ }
65
+ };
66
+ await request.delete(requestOptions);
67
+ }
68
+ catch (err) {
69
+ this.handleRejectedODataJsonPromise(err);
70
+ }
71
+ };
72
+ if (args.options.force) {
73
+ await removeDirectoryExtension();
74
+ }
75
+ else {
76
+ const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove directory extension '${args.options.id || args.options.name}' from application '${args.options.appObjectId || args.options.appId || args.options.appName}'?` });
77
+ if (result) {
78
+ await removeDirectoryExtension();
79
+ }
80
+ }
81
+ }
82
+ async getAppObjectId(options) {
83
+ if (options.appObjectId) {
84
+ return options.appObjectId;
85
+ }
86
+ if (options.appId) {
87
+ return (await entraApp.getAppRegistrationByAppId(options.appId, ["id"])).id;
88
+ }
89
+ return (await entraApp.getAppRegistrationByAppName(options.appName, ["id"])).id;
90
+ }
91
+ }
92
+ export default new GraphDirectoryExtensionRemoveCommand();
93
+ //# sourceMappingURL=directoryextension-remove.js.map
@@ -1,6 +1,9 @@
1
1
  const prefix = 'graph';
2
2
  export default {
3
3
  CHANGELOG_LIST: `${prefix} changelog list`,
4
+ DIRECTORYEXTENSION_ADD: `${prefix} directoryextension add`,
5
+ DIRECTORYEXTENSION_GET: `${prefix} directoryextension get`,
6
+ DIRECTORYEXTENSION_REMOVE: `${prefix} directoryextension remove`,
4
7
  SCHEMAEXTENSION_ADD: `${prefix} schemaextension add`,
5
8
  SCHEMAEXTENSION_GET: `${prefix} schemaextension get`,
6
9
  SCHEMAEXTENSION_LIST: `${prefix} schemaextension list`,
@@ -9,6 +9,7 @@ import { formatting } from '../../../../utils/formatting.js';
9
9
  import { validation } from '../../../../utils/validation.js';
10
10
  import SpoCommand from '../../../base/SpoCommand.js';
11
11
  import commands from '../../commands.js';
12
+ const BannerWebPartId = 'cbe7b0a9-3504-44dd-a3a3-0e5cacd07788';
12
13
  class SpoPageHeaderSetCommand extends SpoCommand {
13
14
  get name() {
14
15
  return commands.PAGE_HEADER_SET;
@@ -28,8 +29,8 @@ class SpoPageHeaderSetCommand extends SpoCommand {
28
29
  }
29
30
  async commandAction(logger, args) {
30
31
  const noPageHeader = {
31
- "id": "cbe7b0a9-3504-44dd-a3a3-0e5cacd07788",
32
- "instanceId": "cbe7b0a9-3504-44dd-a3a3-0e5cacd07788",
32
+ "id": BannerWebPartId,
33
+ "instanceId": BannerWebPartId,
33
34
  "title": "Title Region",
34
35
  "description": "Title Region Description",
35
36
  "serverProcessedContent": {
@@ -50,8 +51,8 @@ class SpoPageHeaderSetCommand extends SpoCommand {
50
51
  }
51
52
  };
52
53
  const defaultPageHeader = {
53
- "id": "cbe7b0a9-3504-44dd-a3a3-0e5cacd07788",
54
- "instanceId": "cbe7b0a9-3504-44dd-a3a3-0e5cacd07788",
54
+ "id": BannerWebPartId,
55
+ "instanceId": BannerWebPartId,
55
56
  "title": "Title Region",
56
57
  "description": "Title Region Description",
57
58
  "serverProcessedContent": {
@@ -72,8 +73,8 @@ class SpoPageHeaderSetCommand extends SpoCommand {
72
73
  }
73
74
  };
74
75
  const customPageHeader = {
75
- "id": "cbe7b0a9-3504-44dd-a3a3-0e5cacd07788",
76
- "instanceId": "cbe7b0a9-3504-44dd-a3a3-0e5cacd07788",
76
+ "id": BannerWebPartId,
77
+ "instanceId": BannerWebPartId,
77
78
  "title": "Title Region",
78
79
  "description": "Title Region Description",
79
80
  "serverProcessedContent": {
@@ -177,6 +178,14 @@ class SpoPageHeaderSetCommand extends SpoCommand {
177
178
  title = pageData.Title;
178
179
  topicHeader = topicHeader || pageData.TopicHeader || "";
179
180
  }
181
+ const pageControls = JSON.parse(pageData.CanvasContent1);
182
+ //In the new design page header is is a configurable Banner webpart in the first full-width section
183
+ const headerControl = pageControls.find(control => control?.position?.zoneIndex === 1 && control?.position?.sectionFactor === 0 && control?.webPartId === BannerWebPartId);
184
+ const isStandardPageHeader = pageData.LayoutWebpartsContent !== '[]';
185
+ //LayoutWebpartsContent represents standard page header
186
+ if (!isStandardPageHeader) {
187
+ header = headerControl?.webPartData || header;
188
+ }
180
189
  header.properties.title = title;
181
190
  header.properties.textAlignment = args.options.textAlignment || 'Left';
182
191
  header.properties.showTopicHeader = args.options.showTopicHeader || false;
@@ -232,8 +241,39 @@ class SpoPageHeaderSetCommand extends SpoCommand {
232
241
  }
233
242
  }
234
243
  const requestBody = {
235
- LayoutWebpartsContent: JSON.stringify([header])
244
+ LayoutWebpartsContent: JSON.stringify([header]),
245
+ CanvasContent1: canvasContent
236
246
  };
247
+ if (!isStandardPageHeader) {
248
+ requestBody.LayoutWebpartsContent = '[]';
249
+ header.properties.title = topicHeader;
250
+ if (headerControl) {
251
+ headerControl.webPartData = header;
252
+ }
253
+ else {
254
+ for (const pageControl of pageControls) {
255
+ if (pageControl?.position?.sectionIndex) {
256
+ pageControl.position.sectionIndex += pageControl.position.sectionIndex;
257
+ }
258
+ }
259
+ pageControls.push({
260
+ id: BannerWebPartId,
261
+ controlType: 3,
262
+ displayMode: 2,
263
+ emphasis: {},
264
+ position: {
265
+ zoneIndex: 1,
266
+ sectionFactor: 0,
267
+ layoutIndex: 1,
268
+ controlIndex: 1,
269
+ sectionIndex: 1
270
+ },
271
+ webPartId: BannerWebPartId,
272
+ webPartData: header
273
+ });
274
+ }
275
+ requestBody.CanvasContent1 = JSON.stringify(pageControls);
276
+ }
237
277
  if (title) {
238
278
  requestBody.Title = title;
239
279
  }
@@ -249,9 +289,6 @@ class SpoPageHeaderSetCommand extends SpoCommand {
249
289
  if (bannerImageUrl) {
250
290
  requestBody.BannerImageUrl = bannerImageUrl;
251
291
  }
252
- if (canvasContent) {
253
- requestBody.CanvasContent1 = canvasContent;
254
- }
255
292
  requestOptions = {
256
293
  url: `${args.options.webUrl}/_api/sitepages/pages/GetByUrl('sitepages/${formatting.encodeQueryParameter(pageFullName)}')/SavePageAsDraft`,
257
294
  headers: {
@@ -0,0 +1,81 @@
1
+ import { cli } from '../../../../cli/cli.js';
2
+ import request from '../../../../request.js';
3
+ import { spo } from '../../../../utils/spo.js';
4
+ import { urlUtil } from '../../../../utils/urlUtil.js';
5
+ import { validation } from '../../../../utils/validation.js';
6
+ import SpoCommand from '../../../base/SpoCommand.js';
7
+ import commands from '../../commands.js';
8
+ import { Page } from './Page.js';
9
+ import { z } from 'zod';
10
+ import { globalOptionsZod } from '../../../../Command.js';
11
+ import { zod } from '../../../../utils/zod.js';
12
+ const options = globalOptionsZod
13
+ .extend({
14
+ webUrl: zod.alias('u', z.string()
15
+ .refine(url => validation.isValidSharePointUrl(url) === true, url => ({
16
+ message: `'${url}' is not a valid SharePoint Online site URL.`
17
+ }))),
18
+ pageName: zod.alias('n', z.string()),
19
+ section: zod.alias('s', z.number()),
20
+ force: zod.alias('f', z.boolean().optional())
21
+ })
22
+ .strict();
23
+ class SpoPageSectionRemoveCommand extends SpoCommand {
24
+ get name() {
25
+ return commands.PAGE_SECTION_REMOVE;
26
+ }
27
+ get description() {
28
+ return 'Removes the specified section from the modern page';
29
+ }
30
+ get schema() {
31
+ return options;
32
+ }
33
+ async commandAction(logger, args) {
34
+ if (args.options.force) {
35
+ await this.removeSection(logger, args);
36
+ }
37
+ else {
38
+ const result = await cli.promptForConfirmation({ message: `Are you sure you want to remove section ${args.options.section} from '${args.options.pageName}'?` });
39
+ if (result) {
40
+ await this.removeSection(logger, args);
41
+ }
42
+ }
43
+ }
44
+ async removeSection(logger, args) {
45
+ try {
46
+ if (this.verbose) {
47
+ await logger.logToStderr(`Removing modern page section ${args.options.pageName} - ${args.options.section}...`);
48
+ }
49
+ const reqDigest = await spo.getRequestDigest(args.options.webUrl);
50
+ const clientSidePage = await Page.getPage(args.options.pageName, args.options.webUrl, logger, this.debug, this.verbose);
51
+ const sectionToDelete = clientSidePage.sections
52
+ .findIndex(section => section.order === args.options.section);
53
+ if (sectionToDelete === -1) {
54
+ throw new Error(`Section ${args.options.section} not found`);
55
+ }
56
+ clientSidePage.sections.splice(sectionToDelete, 1);
57
+ const updatedContent = clientSidePage.toHtml();
58
+ const requestOptions = {
59
+ url: `${args.options
60
+ .webUrl}/_api/web/GetFileByServerRelativePath(DecodedUrl='${urlUtil.getServerRelativeSiteUrl(args.options.webUrl)}/sitepages/${args.options.pageName}')/ListItemAllFields`,
61
+ headers: {
62
+ 'X-RequestDigest': reqDigest.FormDigestValue,
63
+ 'content-type': 'application/json;odata=nometadata',
64
+ 'X-HTTP-Method': 'MERGE',
65
+ 'IF-MATCH': '*',
66
+ accept: 'application/json;odata=nometadata'
67
+ },
68
+ data: {
69
+ CanvasContent1: updatedContent
70
+ },
71
+ responseType: 'json'
72
+ };
73
+ return request.post(requestOptions);
74
+ }
75
+ catch (err) {
76
+ this.handleRejectedODataJsonPromise(err);
77
+ }
78
+ }
79
+ }
80
+ export default new SpoPageSectionRemoveCommand();
81
+ //# sourceMappingURL=page-section-remove.js.map
@@ -221,6 +221,7 @@ export default {
221
221
  PAGE_SECTION_ADD: `${prefix} page section add`,
222
222
  PAGE_SECTION_GET: `${prefix} page section get`,
223
223
  PAGE_SECTION_LIST: `${prefix} page section list`,
224
+ PAGE_SECTION_REMOVE: `${prefix} page section remove`,
224
225
  PAGE_TEMPLATE_LIST: `${prefix} page template list`,
225
226
  PAGE_TEMPLATE_REMOVE: `${prefix} page template remove`,
226
227
  PAGE_TEXT_ADD: `${prefix} page text add`,
package/dist/request.js CHANGED
@@ -132,6 +132,7 @@ class Request {
132
132
  throw 'Logger not set on the request object';
133
133
  }
134
134
  this.updateRequestForCloudType(options, auth.connection.cloudType);
135
+ this.removeDoubleSlashes(options);
135
136
  try {
136
137
  let accessToken = '';
137
138
  if (options.headers && options.headers['x-anonymous']) {
@@ -187,6 +188,10 @@ class Request {
187
188
  const cloudUrl = Auth.getEndpointForResource(hostname, cloudType);
188
189
  options.url = options.url.replace(hostname, cloudUrl);
189
190
  }
191
+ removeDoubleSlashes(options) {
192
+ options.url = options.url.substring(0, 8) +
193
+ options.url.substring(8).replace('//', '/');
194
+ }
190
195
  createProxyConfigFromUrl(url) {
191
196
  const parsedUrl = new URL(url);
192
197
  const port = parsedUrl.port || (url.toLowerCase().startsWith('https') ? 443 : 80);
@@ -0,0 +1,25 @@
1
+ import { formatting } from './formatting.js';
2
+ import { odata } from './odata.js';
3
+ export const directoryExtension = {
4
+ /**
5
+ * Get a directory extension by its name registered for an application.
6
+ * @param name Role definition display name.
7
+ * @param appObjectId Application object id.
8
+ * @param properties List of properties to include in the response.
9
+ * @returns The directory extensions.
10
+ * @throws Error when directory extension was not found.
11
+ */
12
+ async getDirectoryExtensionByName(name, appObjectId, properties) {
13
+ let url = `https://graph.microsoft.com/v1.0/applications/${appObjectId}/extensionProperties?$filter=name eq '${formatting.encodeQueryParameter(name)}'`;
14
+ if (properties) {
15
+ url += `&$select=${properties.join(',')}`;
16
+ }
17
+ const extensionProperties = await odata.getAllItems(url);
18
+ if (extensionProperties.length === 0) {
19
+ throw `The specified directory extension '${name}' does not exist.`;
20
+ }
21
+ // there can be only one directory extension with a given name
22
+ return extensionProperties[0];
23
+ }
24
+ };
25
+ //# sourceMappingURL=directoryExtension.js.map
@@ -1,6 +1,8 @@
1
1
  import fs from 'fs';
2
2
  import request from '../request.js';
3
3
  import { odata } from './odata.js';
4
+ import { formatting } from './formatting.js';
5
+ import { cli } from '../cli/cli.js';
4
6
  async function getCertificateBase64Encoded({ options, logger, debug }) {
5
7
  if (options.certificateBase64Encoded) {
6
8
  return options.certificateBase64Encoded;
@@ -278,6 +280,32 @@ export const entraApp = {
278
280
  await logger.logToStderr(`OAuth2 permissions: ${JSON.stringify(entraApp.appPermissions.flatMap(permission => permission.scope), null, 2)}`);
279
281
  }
280
282
  return resolvedApis;
283
+ },
284
+ async getAppRegistrationByAppId(appId, properties) {
285
+ let url = `https://graph.microsoft.com/v1.0/applications?$filter=appId eq '${appId}'`;
286
+ if (properties) {
287
+ url += `&$select=${properties.join(',')}`;
288
+ }
289
+ const apps = await odata.getAllItems(url);
290
+ if (apps.length === 0) {
291
+ throw `App with appId '${appId}' not found in Microsoft Entra ID`;
292
+ }
293
+ return apps[0];
294
+ },
295
+ async getAppRegistrationByAppName(appName, properties) {
296
+ let url = `https://graph.microsoft.com/v1.0/applications?$filter=displayName eq '${formatting.encodeQueryParameter(appName)}'`;
297
+ if (properties) {
298
+ url += `&$select=${properties.join(',')}`;
299
+ }
300
+ const apps = await odata.getAllItems(url);
301
+ if (apps.length === 0) {
302
+ throw `App with name '${appName}' not found in Microsoft Entra ID`;
303
+ }
304
+ if (apps.length > 1) {
305
+ const resultAsKeyValuePair = formatting.convertArrayToHashTable('id', apps);
306
+ return await cli.handleMultipleResultsFound(`Multiple apps with name '${appName}' found in Microsoft Entra ID.`, resultAsKeyValuePair);
307
+ }
308
+ return apps[0];
281
309
  }
282
310
  };
283
311
  //# sourceMappingURL=entraApp.js.map