From bb45f87fa4b700170d26e4854c5e5b22a906431c Mon Sep 17 00:00:00 2001 From: Martin Lingstuyl Date: Thu, 2 Nov 2023 16:38:28 +0100 Subject: [PATCH 1/7] Adds command 'tenant people profilecardproperty add'. Closes #5617 --- .eslintrc.cjs | 2 + .../people/people-profilecardproperty-add.mdx | 171 ++++++++++++ docs/src/config/sidebars.js | 9 + src/m365/tenant/commands.ts | 1 + .../people-profilecardproperty-add.spec.ts | 250 ++++++++++++++++++ .../people/people-profilecardproperty-add.ts | 156 +++++++++++ .../commands/people/profileCardProperties.ts | 23 ++ 7 files changed, 612 insertions(+) create mode 100644 docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx create mode 100644 src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts create mode 100644 src/m365/tenant/commands/people/people-profilecardproperty-add.ts create mode 100644 src/m365/tenant/commands/people/profileCardProperties.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 7cda2cdbd03..cc93a877e20 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -16,6 +16,7 @@ const dictionary = [ 'audit', 'bin', 'builder', + 'card', 'catalog', 'checklist', 'client', @@ -68,6 +69,7 @@ const dictionary = [ 'permission', 'place', 'policy', + 'profile', 'property', 'records', 'recycle', diff --git a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx new file mode 100644 index 00000000000..be6cdf6ae92 --- /dev/null +++ b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx @@ -0,0 +1,171 @@ +import Global from '/docs/cmd/_global.mdx'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# tenant people profilecardproperty add + +Adds a custom attribute as a profile card property + +## Usage + +```sh +m365 tenant people profilecardproperty add [options] +``` + +## Options + +```md definition-list +`-n, --name ` +: The name of the property to add. Allowed values: `userPrincipalName`, `faxNumber`, `streetAddress`, `postalCode`, `state`, `mailNickname`, `customAttribute1`, `customAttribute2`, `customAttribute3`, `customAttribute4`, `customAttribute5`, `customAttribute6`, `customAttribute7`, `customAttribute8`, `customAttribute9`, `customAttribute10`, `customAttribute11`, `customAttribute12`, `customAttribute13`, `customAttribute14`, `customAttribute15` + +`-d, --displayName [displayName]` +: The display name of a property, only use together with custom extension attributes. +``` + + + +## Remarks + +:::info + +To use this command you must be either **Tenant Administrator** or **Global Administrator**. + +::: + +:::info + +You can specify localized values for the `displayName` as well. These can be entered by suffixing the displayName option with a language code: `--displayName-nl-NL "Kostencentrum" --displayName-de "Kostenstelle"`. + +::: + +## Examples + +Add the UPN as a profile property to the profile cards + +```sh +m365 tenant people profilecardproperty add --name userPrincipalName +``` + +Add a custom extension attribute Cost Center as a profile property to the profile cards + +```sh +m365 tenant people profilecardproperty add --name customAttribute1 --displayName 'Cost Center' +``` + +Add a custom extension attribute Cost Center as a profile property to the profile cards with a dutch localization + +```sh +m365 tenant people profilecardproperty add --name customAttribute1 --displayName 'Cost Center' --displayName-nl-NL 'Kostencentrum' +``` + +## Response + +### Standard response + + + + + ```json + { + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", + "directoryPropertyName": "userPrincipalName", + "annotations": [] + } + ``` + + + + + ```text + @odata.context : https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity + annotations : [] + directoryPropertyName: userPrincipalName + ``` + + + + + ```csv + @odata.context,directoryPropertyName + https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity,userPrincipalName + ``` + + + + + ```md + # tenant people profilecardproperty add --name 'userPrincipalName' + + Date: 11/2/2023 + + Property | Value + ---------|------- + @odata.context | https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity + directoryPropertyName | userPrincipalName + ``` + + + + +### Response with an customAttribute + +When we make use of one of the customAttributes, the response will differ. + + + + + ```json + { + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", + "directoryPropertyName": "customAttribute1", + "annotations": [ + { + "displayName": "Cost center", + "localizations": [ + { + "languageTag": "nl-NL", + "displayName": "Kostenplaats" + } + ] + } + ] + } + ``` + + + + + ```text + @odata.context : https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity + annotations : [{"displayName":"Cost center","localizations":[{"languageTag":"nl-NL","displayName":"Kostenplaats"}]}] + directoryPropertyName: customAttribute1 + ``` + + + + + ```csv + @odata.context,directoryPropertyName + https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity,customAttribute1 + ``` + + + + + ```md + # tenant people profilecardproperty add --name 'customAttribute1' --displayName 'Cost center' --displayName-nl-NL 'Kostenplaats' + + Date: 11/2/2023 + + Property | Value + ---------|------- + @odata.context | https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity + directoryPropertyName | customAttribute1 + ``` + + + + +## More information + +- https://learn.microsoft.com/en-us/graph/add-properties-profilecard \ No newline at end of file diff --git a/docs/src/config/sidebars.js b/docs/src/config/sidebars.js index 0ec3edb862e..f6f226ea5d9 100644 --- a/docs/src/config/sidebars.js +++ b/docs/src/config/sidebars.js @@ -673,6 +673,15 @@ const sidebars = { } ] }, + { + "people": [ + { + type: 'doc', + label: 'people profilecardproperty add', + id: 'cmd/tenant/people/people-profilecardproperty-add' + } + ] + }, { report: [ { diff --git a/src/m365/tenant/commands.ts b/src/m365/tenant/commands.ts index 85a06726e6c..0aaa80c96b1 100644 --- a/src/m365/tenant/commands.ts +++ b/src/m365/tenant/commands.ts @@ -3,6 +3,7 @@ const prefix: string = 'tenant'; export default { ID_GET: `${prefix} id get`, INFO_GET: `${prefix} info get`, + PEOPLE_PROFILECARDPROPERTY_ADD: `${prefix} people profilecardproperty add`, REPORT_ACTIVEUSERCOUNTS: `${prefix} report activeusercounts`, REPORT_ACTIVEUSERDETAIL: `${prefix} report activeuserdetail`, REPORT_OFFICE365ACTIVATIONCOUNTS: `${prefix} report office365activationcounts`, diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts new file mode 100644 index 00000000000..c43f30b0a26 --- /dev/null +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts @@ -0,0 +1,250 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import auth from '../../../../Auth.js'; +import { Cli } from '../../../../cli/Cli.js'; +import { CommandInfo } from '../../../../cli/CommandInfo.js'; +import { Logger } from '../../../../cli/Logger.js'; +import { CommandError } from '../../../../Command.js'; +import request from '../../../../request.js'; +import { telemetry } from '../../../../telemetry.js'; +import { pid } from '../../../../utils/pid.js'; +import { session } from '../../../../utils/session.js'; +import { sinonUtil } from '../../../../utils/sinonUtil.js'; +import commands from '../../commands.js'; +import command from './people-profilecardproperty-add.js'; + +describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { + + //#region Mocked Responses + const propertyResponse = { + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", + "directoryPropertyName": "userPrincipalName", + "annotations": [] + }; + + const customAttributePropertyResponse = { + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", + "directoryPropertyName": "customAttribute1", + "annotations": [ + { + "displayName": "Cost center", + "localizations": [ + { + "languageTag": "nl-NL", + "displayName": "Kostenplaats" + } + ] + } + ] + }; + //#endregion + + let log: string[]; + let logger: Logger; + let loggerLogSpy: sinon.SinonSpy; + let commandInfo: CommandInfo; + + before(() => { + sinon.stub(auth, 'restoreAuth').resolves(); + sinon.stub(telemetry, 'trackEvent').returns(); + sinon.stub(pid, 'getProcessName').returns(''); + sinon.stub(session, 'getId').returns(''); + auth.service.connected = true; + commandInfo = Cli.getCommandInfo(command); + }); + + beforeEach(() => { + log = []; + logger = { + log: async (msg: string) => { + log.push(msg); + }, + logRaw: async (msg: string) => { + log.push(msg); + }, + logToStderr: async (msg: string) => { + log.push(msg); + } + }; + loggerLogSpy = sinon.spy(logger, 'log'); + }); + + afterEach(() => { + sinonUtil.restore([ + request.post + ]); + }); + + after(() => { + sinon.restore(); + auth.service.connected = false; + }); + + it('has correct name', () => { + assert.strictEqual(command.name.startsWith(commands.PEOPLE_PROFILECARDPROPERTY_ADD), true); + }); + + it('has a description', () => { + assert.notStrictEqual(command.description, null); + }); + + it('fails validation if the name is not a valid value.', async () => { + const actual = await command.validate({ options: { name: 'invalid' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('fails validation if the name is customAttribute1 and the displayName option is not used.', async () => { + const actual = await command.validate({ options: { name: 'customAttribute1' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('fails validation if a localization property has an invalid name.', async () => { + const actual = await command.validate({ options: { name: 'customAttribute1', displayName: 'Cost center', 'invalid-nl-NL': 'Kostenplaats' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('fails validation if a the localization option is used for a non-extension attribute.', async () => { + const actual = await command.validate({ options: { name: 'userPrincipalName', 'displayName-nl-NL': 'Kostenplaats' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('fails validation if the displayName option is used for a non-extension attribute.', async () => { + const actual = await command.validate({ options: { name: 'userPrincipalName', displayName: 'Cost center' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('passes validation if the name is set to userPrincipalName.', async () => { + const actual = await command.validate({ options: { name: 'userPrincipalName' } }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('passes validation if the name is customAttribute1 and the displayName option is used.', async () => { + const actual = await command.validate({ options: { name: 'customAttribute1', displayName: 'Cost center' } }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('passes validation if a correct localization option is used.', async () => { + const actual = await command.validate({ options: { name: 'customAttribute1', displayName: 'Cost center', 'displayName-nl-NL': 'Kostenplaats' } }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('correctly adds profile card property for userPrincipalName', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return propertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await assert.doesNotReject(command.action(logger, { options: { name: 'userPrincipalName' } })); + assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); + }); + + it('correctly adds profile card property for userPrincipalName (debug)', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return propertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await assert.doesNotReject(command.action(logger, { options: { name: 'userPrincipalName', debug: true } })); + assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); + }); + + it('correctly adds profile card property for fax', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return propertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await assert.doesNotReject(command.action(logger, { options: { name: 'faxNumber' } })); + assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); + }); + + it('correctly adds profile card property for state', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return propertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await command.action(logger, { options: { name: 'state' } }); + assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); + }); + + it('correctly adds profile card property for mailNickname', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return propertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await command.action(logger, { options: { name: 'mailNickname' } }); + assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); + }); + + it('correctly adds profile card property for an customAttribute', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return customAttributePropertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await command.action(logger, { options: { name: 'customAttribute1', displayName: 'Cost center' } }); + assert(loggerLogSpy.calledOnceWithExactly(customAttributePropertyResponse)); + }); + + it('correctly adds profile card property for an customAttribute with a localization', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return customAttributePropertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await command.action(logger, { options: { name: 'customAttribute1', displayName: 'Cost center', 'displayName-nl-NL': 'Kostenplaats' } }); + assert(loggerLogSpy.calledOnceWithExactly(customAttributePropertyResponse)); + }); + + it('fails when the addition conflicts with an existing property', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + throw { + "error": { + "code": "409", + "message": "Conflicts with existing entry", + "innerError": { + "peopleAdminErrorCode": "PeopleAdminItemConflict", + "peopleAdminRequestId": "36d1ea9e-83f8-49c9-7ebc-6f6c24ca03cc", + "peopleAdminClientRequestId": "174cf6d3-6cde-46a8-b4f3-5d4d07354ac2", + "date": "2023-11-02T15:22:36", + "request-id": "174cf6d3-6cde-46a8-b4f3-5d4d07354ac2", + "client-request-id": "174cf6d3-6cde-46a8-b4f3-5d4d07354ac2" + } + } + }; + } + + throw `Invalid request ${opts.url}`; + }); + + await assert.rejects(command.action(logger, { + options: { + name: 'userPrincipalName' + } + }), new CommandError(`Conflicts with existing entry`)); + }); +}); \ No newline at end of file diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts new file mode 100644 index 00000000000..b38d0fd7d27 --- /dev/null +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -0,0 +1,156 @@ +import { Logger } from '../../../../cli/Logger.js'; +import GlobalOptions from '../../../../GlobalOptions.js'; +import request from '../../../../request.js'; +import GraphCommand from '../../../base/GraphCommand.js'; +import commands from '../../commands.js'; +import { profileCardPropertyNames } from './profileCardProperties.js'; + +interface CommandArgs { + options: Options; +} + +interface Options extends GlobalOptions { + name: string; + displayName?: string; +} + +class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { + public get name(): string { + return commands.PEOPLE_PROFILECARDPROPERTY_ADD; + } + + public get description(): string { + return 'Adds a custom attribute as a profile card property'; + } + + constructor() { + super(); + + this.#initTelemetry(); + this.#initOptions(); + this.#initValidators(); + } + + #initTelemetry(): void { + this.telemetry.push((args: CommandArgs) => { + Object.assign(this.telemetryProperties, { + name: args.options.name, + displayName: typeof args.options.displayName !== 'undefined' + }); + }); + } + + #initOptions(): void { + this.options.unshift( + { + option: '-n, --name ', + autocomplete: profileCardPropertyNames + }, + { + option: '-d, --displayName [displayName]' + } + ); + } + + #initValidators(): void { + this.validators.push( + async (args: CommandArgs) => { + const propertyName = args.options.name.toLowerCase(); + + if (profileCardPropertyNames.every(n => n.toLowerCase() !== propertyName)) { + return `${args.options.name} is not a valid value for name. Allowed values are ${profileCardPropertyNames.join(', ')}`; + } + + if (propertyName.startsWith("customattribute") && args.options.displayName === undefined) { + return `The option 'displayName' is required when adding customAttributes as profile card properties`; + } + + if (!propertyName.startsWith("customattribute") && args.options.displayName !== undefined) { + return `The option 'displayName' can only be used when adding customAttributes as profile card properties`; + } + + const excludeOptions: string[] = ['name', 'displayName', 'debug', 'verbose', 'output']; + const unknownOptions = Object.keys(args.options).filter(key => excludeOptions.indexOf(key) === -1); + + if (!propertyName.startsWith('customattribute') && unknownOptions.length > 0) { + return `Unknown options like ${unknownOptions.join(', ')} are only supported with customAttributes`; + } + + if (propertyName.startsWith('customattribute')) { + const wronglyFormattedOptions = unknownOptions.filter(key => !key.toLowerCase().startsWith('displayname-')); + if (wronglyFormattedOptions.length > 0) { + return `Wrong option format detected for the following option(s): ${wronglyFormattedOptions.join(', ')}'. When adding localizations for customAttributes, use the format displayName-.`; + } + } + + return true; + } + ); + } + + public allowUnknownOptions(): boolean | undefined { + return true; + } + + public async commandAction(logger: Logger, args: CommandArgs): Promise { + if (this.verbose) { + await logger.logToStderr(`Adding '${args.options.name}' as a profile card property...`); + } + + const requestOptions: any = { + url: `${this.resource}/v1.0/admin/people/profileCardProperties`, + headers: { + 'content-type': 'application/json' + }, + responseType: 'json', + data: { + directoryPropertyName: args.options.name, + annotations: this.getAnnotations(args.options) + } + }; + + try { + const response: any = await request.post(requestOptions); + + await logger.log(response); + } + catch (err: any) { + this.handleRejectedODataJsonPromise(err); + } + } + + private getAnnotations(options: Options): { displayName: string, localizations?: { languageTag: string, displayName: string }[] }[] { + if (!options.displayName) { + return []; + } + + return [ + { + displayName: options.displayName!, + localizations: this.getLocalizations(options) + } + ]; + } + + private getLocalizations(options: Options): { languageTag: string, displayName: string }[] { + const excludeOptions: string[] = ['name', 'displayName', 'debug', 'verbose', 'output']; + const unknownOptions = Object.keys(options).filter(key => excludeOptions.indexOf(key) === -1); + + if (unknownOptions.length === 0) { + return []; + } + + const localizations: { languageTag: string, displayName: string }[] = []; + + unknownOptions.forEach(key => { + localizations.push({ + languageTag: key.replace('displayName-', ''), + displayName: options[key] + }); + }); + + return localizations; + } +} + +export default new TenantPeopleProfileCardPropertyAddCommand(); \ No newline at end of file diff --git a/src/m365/tenant/commands/people/profileCardProperties.ts b/src/m365/tenant/commands/people/profileCardProperties.ts new file mode 100644 index 00000000000..63ec347e6a4 --- /dev/null +++ b/src/m365/tenant/commands/people/profileCardProperties.ts @@ -0,0 +1,23 @@ +export const profileCardPropertyNames: string[] = [ + 'userPrincipalName', + 'faxNumber', + 'streetAddress', + 'postalCode', + 'state', + 'mailNickname', + 'customAttribute1', + 'customAttribute2', + 'customAttribute3', + 'customAttribute4', + 'customAttribute5', + 'customAttribute6', + 'customAttribute7', + 'customAttribute8', + 'customAttribute9', + 'customAttribute10', + 'customAttribute11', + 'customAttribute12', + 'customAttribute13', + 'customAttribute14', + 'customAttribute15' +]; \ No newline at end of file From 96c59f9148907afbf939092f114a759ff2535db0 Mon Sep 17 00:00:00 2001 From: Martin Lingstuyl Date: Thu, 2 Nov 2023 21:50:44 +0100 Subject: [PATCH 2/7] Resolve comments --- .../people/people-profilecardproperty-add.mdx | 23 +++++++++++-------- .../people-profilecardproperty-add.spec.ts | 6 ++--- .../people/people-profilecardproperty-add.ts | 19 ++++++++++++--- .../commands/people/profileCardProperties.ts | 6 ++--- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx index be6cdf6ae92..6854e787377 100644 --- a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx +++ b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx @@ -4,7 +4,7 @@ import TabItem from '@theme/TabItem'; # tenant people profilecardproperty add -Adds a custom attribute as a profile card property +Adds an additional attribute to the profile card properties ## Usage @@ -16,10 +16,10 @@ m365 tenant people profilecardproperty add [options] ```md definition-list `-n, --name ` -: The name of the property to add. Allowed values: `userPrincipalName`, `faxNumber`, `streetAddress`, `postalCode`, `state`, `mailNickname`, `customAttribute1`, `customAttribute2`, `customAttribute3`, `customAttribute4`, `customAttribute5`, `customAttribute6`, `customAttribute7`, `customAttribute8`, `customAttribute9`, `customAttribute10`, `customAttribute11`, `customAttribute12`, `customAttribute13`, `customAttribute14`, `customAttribute15` +: The name of the property to add. Allowed values: `userPrincipalName`, `fax`, `streetAddress`, `postalCode`, `stateOrProvince`, `alias`, `customAttribute1`, `customAttribute2`, `customAttribute3`, `customAttribute4`, `customAttribute5`, `customAttribute6`, `customAttribute7`, `customAttribute8`, `customAttribute9`, `customAttribute10`, `customAttribute11`, `customAttribute12`, `customAttribute13`, `customAttribute14`, `customAttribute15` `-d, --displayName [displayName]` -: The display name of a property, only use together with custom extension attributes. +: The display name of a property, only use this together with a custom extension attribute. ``` @@ -34,25 +34,25 @@ To use this command you must be either **Tenant Administrator** or **Global Admi :::info -You can specify localized values for the `displayName` as well. These can be entered by suffixing the displayName option with a language code: `--displayName-nl-NL "Kostencentrum" --displayName-de "Kostenstelle"`. +You can specify localized values for the `displayName` as well. These can be entered by suffixing the displayName option with a language code: `--displayName-nl-NL "Kostencentrum"`, `--displayName-de "Kostenstelle"`. ::: ## Examples -Add the UPN as a profile property to the profile cards +Add the UPN as a profile property to the profile cards properties ```sh m365 tenant people profilecardproperty add --name userPrincipalName ``` -Add a custom extension attribute Cost Center as a profile property to the profile cards +Add a custom extension attribute _Cost Center_ as a profile property to the profile cards properties ```sh m365 tenant people profilecardproperty add --name customAttribute1 --displayName 'Cost Center' ``` -Add a custom extension attribute Cost Center as a profile property to the profile cards with a dutch localization +Add a custom extension attribute _Cost Center_ as a profile property to the profile cards properties with a Dutch localization ```sh m365 tenant people profilecardproperty add --name customAttribute1 --displayName 'Cost Center' --displayName-nl-NL 'Kostencentrum' @@ -137,16 +137,17 @@ When we make use of one of the customAttributes, the response will differ. ```text @odata.context : https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity - annotations : [{"displayName":"Cost center","localizations":[{"languageTag":"nl-NL","displayName":"Kostenplaats"}]}] directoryPropertyName: customAttribute1 + displayName : Cost center + displayName-nl-NL : Kostenplaats ``` ```csv - @odata.context,directoryPropertyName - https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity,customAttribute1 + @odata.context,directoryPropertyName,displayName,displayName-nl-NL +https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity,customAttribute1,Cost center,Kostenplaats ``` @@ -161,6 +162,8 @@ When we make use of one of the customAttributes, the response will differ. ---------|------- @odata.context | https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity directoryPropertyName | customAttribute1 + displayName | Cost center + displayName-nl-NL | Kostenplaats ``` diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts index c43f30b0a26..4e0c7599693 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts @@ -163,7 +163,7 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { throw `Invalid request ${opts.url}`; }); - await assert.doesNotReject(command.action(logger, { options: { name: 'faxNumber' } })); + await assert.doesNotReject(command.action(logger, { options: { name: 'fax' } })); assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); }); @@ -176,7 +176,7 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { throw `Invalid request ${opts.url}`; }); - await command.action(logger, { options: { name: 'state' } }); + await command.action(logger, { options: { name: 'stateOrProvince' } }); assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); }); @@ -189,7 +189,7 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { throw `Invalid request ${opts.url}`; }); - await command.action(logger, { options: { name: 'mailNickname' } }); + await command.action(logger, { options: { name: 'alias' } }); assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); }); diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts index b38d0fd7d27..a531d072733 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -20,7 +20,7 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { } public get description(): string { - return 'Adds a custom attribute as a profile card property'; + return 'Adds an additional attribute to the profile card properties'; } constructor() { @@ -70,7 +70,7 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { } const excludeOptions: string[] = ['name', 'displayName', 'debug', 'verbose', 'output']; - const unknownOptions = Object.keys(args.options).filter(key => excludeOptions.indexOf(key) === -1); + const unknownOptions = Object.keys(args.options).filter(key => !excludeOptions.includes(key)); if (!propertyName.startsWith('customattribute') && unknownOptions.length > 0) { return `Unknown options like ${unknownOptions.join(', ')} are only supported with customAttributes`; @@ -112,6 +112,19 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { try { const response: any = await request.post(requestOptions); + if (args.options.output !== 'json') { + const annotation = response.annotations[0]; + + if (annotation) { + response.displayName = annotation.displayName; + annotation.localizations.forEach((l: { languageTag: string, displayName: string }) => { + response[`displayName-${l.languageTag}`] = l.displayName; + }); + } + + delete response.annotations; + } + await logger.log(response); } catch (err: any) { @@ -134,7 +147,7 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { private getLocalizations(options: Options): { languageTag: string, displayName: string }[] { const excludeOptions: string[] = ['name', 'displayName', 'debug', 'verbose', 'output']; - const unknownOptions = Object.keys(options).filter(key => excludeOptions.indexOf(key) === -1); + const unknownOptions = Object.keys(options).filter(key => !excludeOptions.includes(key)); if (unknownOptions.length === 0) { return []; diff --git a/src/m365/tenant/commands/people/profileCardProperties.ts b/src/m365/tenant/commands/people/profileCardProperties.ts index 63ec347e6a4..6a2abf328b3 100644 --- a/src/m365/tenant/commands/people/profileCardProperties.ts +++ b/src/m365/tenant/commands/people/profileCardProperties.ts @@ -1,10 +1,10 @@ export const profileCardPropertyNames: string[] = [ 'userPrincipalName', - 'faxNumber', + 'fax', 'streetAddress', 'postalCode', - 'state', - 'mailNickname', + 'stateOrProvince', + 'alias', 'customAttribute1', 'customAttribute2', 'customAttribute3', From 86f420b31f8bc802b906b37cab8e09c1a6173f38 Mon Sep 17 00:00:00 2001 From: Martin Lingstuyl Date: Thu, 2 Nov 2023 22:19:52 +0100 Subject: [PATCH 3/7] Updates --- .../people-profilecardproperty-add.spec.ts | 39 +++++++++++++++++-- .../people/people-profilecardproperty-add.ts | 2 +- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts index 4e0c7599693..d99a4151f88 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts @@ -37,6 +37,13 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { } ] }; + + const customAttributePropertyTextResponse = { + "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", + "directoryPropertyName": "customAttribute1", + "displayName": "Cost center", + "displayName-nl-NL": "Kostenplaats" + }; //#endregion let log: string[]; @@ -167,7 +174,7 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); }); - it('correctly adds profile card property for state', async () => { + it('correctly adds profile card property for stateOrProvince', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { return propertyResponse; @@ -180,7 +187,7 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); }); - it('correctly adds profile card property for mailNickname', async () => { + it('correctly adds profile card property for alias (json output)', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { return propertyResponse; @@ -189,7 +196,20 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { throw `Invalid request ${opts.url}`; }); - await command.action(logger, { options: { name: 'alias' } }); + await command.action(logger, { options: { name: 'alias', output: 'json' } }); + assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); + }); + + it('correctly adds profile card property for alias (text output)', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return propertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await command.action(logger, { options: { name: 'alias', output: 'text' } }); assert(loggerLogSpy.calledOnceWithExactly(propertyResponse)); }); @@ -219,6 +239,19 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { assert(loggerLogSpy.calledOnceWithExactly(customAttributePropertyResponse)); }); + it('correctly adds profile card property for an customAttribute with a localization (text output)', async () => { + sinon.stub(request, 'post').callsFake(async (opts) => { + if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { + return customAttributePropertyResponse; + } + + throw `Invalid request ${opts.url}`; + }); + + await command.action(logger, { options: { name: 'customAttribute1', displayName: 'Cost center', 'displayName-nl-NL': 'Kostenplaats', output: 'text' } }); + assert(loggerLogSpy.calledOnceWithExactly(customAttributePropertyTextResponse)); + }); + it('fails when the addition conflicts with an existing property', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === `https://graph.microsoft.com/v1.0/admin/people/profileCardProperties`) { diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts index a531d072733..dbfba8b4707 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -112,7 +112,7 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { try { const response: any = await request.post(requestOptions); - if (args.options.output !== 'json') { + if (args.options.output && args.options.output !== 'json') { const annotation = response.annotations[0]; if (annotation) { From 11690fc1d74bde822a03f0dbb4bee10811922605 Mon Sep 17 00:00:00 2001 From: Martin Lingstuyl Date: Fri, 3 Nov 2023 07:55:20 +0100 Subject: [PATCH 4/7] Updates --- .../people/people-profilecardproperty-add.mdx | 11 ++++------- .../people/people-profilecardproperty-add.spec.ts | 3 +-- .../people/people-profilecardproperty-add.ts | 14 +++++++------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx index 6854e787377..001f2d7b317 100644 --- a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx +++ b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx @@ -116,7 +116,6 @@ When we make use of one of the customAttributes, the response will differ. ```json { - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", "directoryPropertyName": "customAttribute1", "annotations": [ { @@ -136,18 +135,17 @@ When we make use of one of the customAttributes, the response will differ. ```text - @odata.context : https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity directoryPropertyName: customAttribute1 displayName : Cost center - displayName-nl-NL : Kostenplaats + displayName nl-NL : Kostenplaats ``` ```csv - @odata.context,directoryPropertyName,displayName,displayName-nl-NL -https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity,customAttribute1,Cost center,Kostenplaats + directoryPropertyName,displayName,displayName nl-NL + customAttribute1,Cost center,Kostenplaats ``` @@ -160,10 +158,9 @@ https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$e Property | Value ---------|------- - @odata.context | https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity directoryPropertyName | customAttribute1 displayName | Cost center - displayName-nl-NL | Kostenplaats + displayName nl-NL | Kostenplaats ``` diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts index d99a4151f88..6ae58c392a3 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts @@ -39,10 +39,9 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { }; const customAttributePropertyTextResponse = { - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", "directoryPropertyName": "customAttribute1", "displayName": "Cost center", - "displayName-nl-NL": "Kostenplaats" + "displayName nl-NL": "Kostenplaats" }; //#endregion diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts index dbfba8b4707..b1b7014ced1 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -112,17 +112,17 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { try { const response: any = await request.post(requestOptions); - if (args.options.output && args.options.output !== 'json') { + // Transform the output to make it more readable + if (args.options.output && args.options.output !== 'json' && response.annotations.length > 0) { const annotation = response.annotations[0]; - if (annotation) { - response.displayName = annotation.displayName; - annotation.localizations.forEach((l: { languageTag: string, displayName: string }) => { - response[`displayName-${l.languageTag}`] = l.displayName; - }); - } + response.displayName = annotation.displayName; + annotation.localizations.forEach((l: { languageTag: string, displayName: string }) => { + response[`displayName ${l.languageTag}`] = l.displayName; + }); delete response.annotations; + delete response['@odata.context']; } await logger.log(response); From 0180c505ec2a7cbca1249c3b489354cbfe237722 Mon Sep 17 00:00:00 2001 From: Martin Lingstuyl Date: Fri, 3 Nov 2023 11:31:45 +0100 Subject: [PATCH 5/7] Remove odata.context --- .../cmd/tenant/people/people-profilecardproperty-add.mdx | 7 ++----- .../commands/people/people-profilecardproperty-add.spec.ts | 2 -- .../commands/people/people-profilecardproperty-add.ts | 4 ++-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx index 001f2d7b317..bf337a3cfca 100644 --- a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx +++ b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx @@ -67,7 +67,6 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName ```json { - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", "directoryPropertyName": "userPrincipalName", "annotations": [] } @@ -77,7 +76,6 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName ```text - @odata.context : https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity annotations : [] directoryPropertyName: userPrincipalName ``` @@ -86,8 +84,8 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName ```csv - @odata.context,directoryPropertyName - https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity,userPrincipalName + directoryPropertyName + userPrincipalName ``` @@ -100,7 +98,6 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName Property | Value ---------|------- - @odata.context | https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity directoryPropertyName | userPrincipalName ``` diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts index 6ae58c392a3..c675dc6ad43 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.spec.ts @@ -17,13 +17,11 @@ describe(commands.PEOPLE_PROFILECARDPROPERTY_ADD, () => { //#region Mocked Responses const propertyResponse = { - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", "directoryPropertyName": "userPrincipalName", "annotations": [] }; const customAttributePropertyResponse = { - "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#admin/people/profileCardProperties/$entity", "directoryPropertyName": "customAttribute1", "annotations": [ { diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts index b1b7014ced1..4dc482aafb9 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -100,7 +100,8 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { const requestOptions: any = { url: `${this.resource}/v1.0/admin/people/profileCardProperties`, headers: { - 'content-type': 'application/json' + 'content-type': 'application/json', + accept: 'application/json;odata.metadata=none' }, responseType: 'json', data: { @@ -122,7 +123,6 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { }); delete response.annotations; - delete response['@odata.context']; } await logger.log(response); From abd2004a8020c8758aa6e28a792383cc9e2fa838 Mon Sep 17 00:00:00 2001 From: Jwaegebaert <38426621+Jwaegebaert@users.noreply.github.com> Date: Sat, 4 Nov 2023 21:53:32 +0100 Subject: [PATCH 6/7] Suggestions + force casing to API --- .../people/people-profilecardproperty-add.mdx | 24 ++++++++++++------- .../people/people-profilecardproperty-add.ts | 5 ++-- .../commands/people/profileCardProperties.ts | 12 +++++----- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx index bf337a3cfca..e6eee2eb4a8 100644 --- a/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx +++ b/docs/docs/cmd/tenant/people/people-profilecardproperty-add.mdx @@ -16,7 +16,7 @@ m365 tenant people profilecardproperty add [options] ```md definition-list `-n, --name ` -: The name of the property to add. Allowed values: `userPrincipalName`, `fax`, `streetAddress`, `postalCode`, `stateOrProvince`, `alias`, `customAttribute1`, `customAttribute2`, `customAttribute3`, `customAttribute4`, `customAttribute5`, `customAttribute6`, `customAttribute7`, `customAttribute8`, `customAttribute9`, `customAttribute10`, `customAttribute11`, `customAttribute12`, `customAttribute13`, `customAttribute14`, `customAttribute15` +: The name of the property to add. Allowed values: `UserPrincipalName`, `Fax`, `StreetAddress`, `PostalCode`, `StateOrProvince`, `Alias`, `customAttribute1`, `customAttribute2`, `customAttribute3`, `customAttribute4`, `customAttribute5`, `customAttribute6`, `customAttribute7`, `customAttribute8`, `customAttribute9`, `customAttribute10`, `customAttribute11`, `customAttribute12`, `customAttribute13`, `customAttribute14`, `customAttribute15`. `-d, --displayName [displayName]` : The display name of a property, only use this together with a custom extension attribute. @@ -38,12 +38,18 @@ You can specify localized values for the `displayName` as well. These can be ent ::: +:::caution + +When adding an attribute to a profile card, it takes up to 24 hours for the addition to be displayed. + +::: + ## Examples Add the UPN as a profile property to the profile cards properties ```sh -m365 tenant people profilecardproperty add --name userPrincipalName +m365 tenant people profilecardproperty add --name UserPrincipalName ``` Add a custom extension attribute _Cost Center_ as a profile property to the profile cards properties @@ -67,7 +73,7 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName ```json { - "directoryPropertyName": "userPrincipalName", + "directoryPropertyName": "UserPrincipalName", "annotations": [] } ``` @@ -77,7 +83,7 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName ```text annotations : [] - directoryPropertyName: userPrincipalName + directoryPropertyName: UserPrincipalName ``` @@ -85,26 +91,26 @@ m365 tenant people profilecardproperty add --name customAttribute1 --displayName ```csv directoryPropertyName - userPrincipalName + UserPrincipalName ``` ```md - # tenant people profilecardproperty add --name 'userPrincipalName' + # tenant people profilecardproperty add --name 'UserPrincipalName' Date: 11/2/2023 Property | Value ---------|------- - directoryPropertyName | userPrincipalName + directoryPropertyName | UserPrincipalName ``` -### Response with an customAttribute +### Response with a customAttribute When we make use of one of the customAttributes, the response will differ. @@ -165,4 +171,4 @@ When we make use of one of the customAttributes, the response will differ. ## More information -- https://learn.microsoft.com/en-us/graph/add-properties-profilecard \ No newline at end of file +- https://learn.microsoft.com/graph/add-properties-profilecard diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts index 4dc482aafb9..eca0f090f3d 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -34,7 +34,6 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { #initTelemetry(): void { this.telemetry.push((args: CommandArgs) => { Object.assign(this.telemetryProperties, { - name: args.options.name, displayName: typeof args.options.displayName !== 'undefined' }); }); @@ -97,6 +96,8 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { await logger.logToStderr(`Adding '${args.options.name}' as a profile card property...`); } + const directoryPropertyName = profileCardPropertyNames.find(n => n.toLowerCase() === args.options.name.toLowerCase()); + const requestOptions: any = { url: `${this.resource}/v1.0/admin/people/profileCardProperties`, headers: { @@ -105,7 +106,7 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { }, responseType: 'json', data: { - directoryPropertyName: args.options.name, + directoryPropertyName, annotations: this.getAnnotations(args.options) } }; diff --git a/src/m365/tenant/commands/people/profileCardProperties.ts b/src/m365/tenant/commands/people/profileCardProperties.ts index 6a2abf328b3..9e518d5db36 100644 --- a/src/m365/tenant/commands/people/profileCardProperties.ts +++ b/src/m365/tenant/commands/people/profileCardProperties.ts @@ -1,10 +1,10 @@ export const profileCardPropertyNames: string[] = [ - 'userPrincipalName', - 'fax', - 'streetAddress', - 'postalCode', - 'stateOrProvince', - 'alias', + 'UserPrincipalName', + 'Fax', + 'StreetAddress', + 'PostalCode', + 'StateOrProvince', + 'Alias', 'customAttribute1', 'customAttribute2', 'customAttribute3', From eecc34775e4d33b428ee903b70601fde63868a89 Mon Sep 17 00:00:00 2001 From: Jwaegebaert <38426621+Jwaegebaert@users.noreply.github.com> Date: Sat, 4 Nov 2023 22:01:23 +0100 Subject: [PATCH 7/7] Fixup --- .../commands/people/people-profilecardproperty-add.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts index eca0f090f3d..74026e81d14 100644 --- a/src/m365/tenant/commands/people/people-profilecardproperty-add.ts +++ b/src/m365/tenant/commands/people/people-profilecardproperty-add.ts @@ -92,12 +92,12 @@ class TenantPeopleProfileCardPropertyAddCommand extends GraphCommand { } public async commandAction(logger: Logger, args: CommandArgs): Promise { + const directoryPropertyName = profileCardPropertyNames.find(n => n.toLowerCase() === args.options.name.toLowerCase()); + if (this.verbose) { - await logger.logToStderr(`Adding '${args.options.name}' as a profile card property...`); + await logger.logToStderr(`Adding '${directoryPropertyName}' as a profile card property...`); } - const directoryPropertyName = profileCardPropertyNames.find(n => n.toLowerCase() === args.options.name.toLowerCase()); - const requestOptions: any = { url: `${this.resource}/v1.0/admin/people/profileCardProperties`, headers: {