@pnp/cli-microsoft365 10.0.0-beta.66db729 → 10.0.0-beta.7be7794
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.
- package/allCommands.json +1 -1
- package/allCommandsFull.json +1 -1
- package/dist/m365/commands/login.js +120 -67
- package/dist/m365/entra/commands/m365group/m365group-set.js +138 -68
- package/docs/docs/cmd/entra/m365group/m365group-set.mdx +33 -15
- package/docs/docs/cmd/login.mdx +9 -0
- package/package.json +1 -1
|
@@ -21,7 +21,8 @@ const options = globalOptionsZod
|
|
|
21
21
|
appId: z.string().optional(),
|
|
22
22
|
tenant: z.string().optional(),
|
|
23
23
|
secret: zod.alias('s', z.string().optional()),
|
|
24
|
-
connectionName: z.string().optional()
|
|
24
|
+
connectionName: z.string().optional(),
|
|
25
|
+
ensure: z.boolean().optional()
|
|
25
26
|
})
|
|
26
27
|
.strict();
|
|
27
28
|
class LoginCommand extends Command {
|
|
@@ -67,75 +68,16 @@ class LoginCommand extends Command {
|
|
|
67
68
|
});
|
|
68
69
|
}
|
|
69
70
|
async commandAction(logger, args) {
|
|
70
|
-
// disconnect before re-connecting
|
|
71
71
|
if (this.debug) {
|
|
72
72
|
await logger.logToStderr(`Logging out from Microsoft 365...`);
|
|
73
73
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return options.certificateBase64Encoded;
|
|
82
|
-
}
|
|
83
|
-
return cli.getConfig().get(settingsNames.clientCertificateFile) ||
|
|
84
|
-
cli.getConfig().get(settingsNames.clientCertificateBase64Encoded);
|
|
85
|
-
};
|
|
86
|
-
const login = async () => {
|
|
87
|
-
if (this.verbose) {
|
|
88
|
-
await logger.logToStderr(`Signing in to Microsoft 365...`);
|
|
89
|
-
}
|
|
90
|
-
const authType = args.options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
|
|
91
|
-
auth.connection.appId = args.options.appId || cli.getClientId();
|
|
92
|
-
auth.connection.tenant = args.options.tenant || cli.getTenant();
|
|
93
|
-
auth.connection.name = args.options.connectionName;
|
|
94
|
-
switch (authType) {
|
|
95
|
-
case 'password':
|
|
96
|
-
auth.connection.authType = AuthType.Password;
|
|
97
|
-
auth.connection.userName = args.options.userName;
|
|
98
|
-
auth.connection.password = args.options.password;
|
|
99
|
-
break;
|
|
100
|
-
case 'certificate':
|
|
101
|
-
auth.connection.authType = AuthType.Certificate;
|
|
102
|
-
auth.connection.certificate = getCertificate(args.options);
|
|
103
|
-
auth.connection.thumbprint = args.options.thumbprint;
|
|
104
|
-
auth.connection.password = args.options.password ?? cli.getConfig().get(settingsNames.clientCertificatePassword);
|
|
105
|
-
break;
|
|
106
|
-
case 'identity':
|
|
107
|
-
auth.connection.authType = AuthType.Identity;
|
|
108
|
-
auth.connection.userName = args.options.userName;
|
|
109
|
-
break;
|
|
110
|
-
case 'browser':
|
|
111
|
-
auth.connection.authType = AuthType.Browser;
|
|
112
|
-
break;
|
|
113
|
-
case 'secret':
|
|
114
|
-
auth.connection.authType = AuthType.Secret;
|
|
115
|
-
auth.connection.secret = args.options.secret || cli.getConfig().get(settingsNames.clientSecret);
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
auth.connection.cloudType = args.options.cloud;
|
|
119
|
-
try {
|
|
120
|
-
await auth.ensureAccessToken(auth.defaultResource, logger, this.debug);
|
|
121
|
-
auth.connection.active = true;
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
if (this.debug) {
|
|
125
|
-
await logger.logToStderr('Error:');
|
|
126
|
-
await logger.logToStderr(error);
|
|
127
|
-
await logger.logToStderr('');
|
|
128
|
-
}
|
|
129
|
-
throw new CommandError(error.message);
|
|
130
|
-
}
|
|
131
|
-
const details = auth.getConnectionDetails(auth.connection);
|
|
132
|
-
if (this.debug) {
|
|
133
|
-
details.accessToken = JSON.stringify(auth.connection.accessTokens, null, 2);
|
|
134
|
-
}
|
|
135
|
-
await logger.log(details);
|
|
136
|
-
};
|
|
137
|
-
deactivate();
|
|
138
|
-
await login();
|
|
74
|
+
if (this.shouldLogin(args.options)) {
|
|
75
|
+
auth.connection.deactivate();
|
|
76
|
+
await this.login(logger, args);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
await this.ensureAccessToken(logger);
|
|
80
|
+
}
|
|
139
81
|
}
|
|
140
82
|
async action(logger, args) {
|
|
141
83
|
try {
|
|
@@ -147,6 +89,117 @@ class LoginCommand extends Command {
|
|
|
147
89
|
await this.initAction(args, logger);
|
|
148
90
|
await this.commandAction(logger, args);
|
|
149
91
|
}
|
|
92
|
+
shouldLogin(options) {
|
|
93
|
+
if (!auth.connection.active) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (!options.ensure) {
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
const authType = options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
|
|
100
|
+
if (authType !== auth.connection.authType) {
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
if (options.cloud !== auth.connection.cloudType) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
if (options.appId && options.appId !== auth.connection.appId) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
if (options.tenant && options.tenant !== auth.connection.tenant) {
|
|
110
|
+
return true;
|
|
111
|
+
}
|
|
112
|
+
if (authType === AuthType.Password && (options.password && options.userName !== auth.connection.userName)) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
if (authType === AuthType.Certificate && (options.certificateFile && (auth.connection.certificate !== fs.readFileSync(options.certificateFile, 'base64')))) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
if (authType === AuthType.Identity && (options.userName && options.userName !== auth.connection.userName)) {
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
if (authType === AuthType.Secret && (options.secret && options.secret !== auth.connection.secret)) {
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
const now = new Date();
|
|
125
|
+
const accessToken = auth.connection.accessTokens[auth.defaultResource];
|
|
126
|
+
const expiresOn = accessToken && accessToken.expiresOn ?
|
|
127
|
+
// if expiresOn is serialized from the service file, it's set as a string
|
|
128
|
+
// if it's coming from MSAL, it's a Date
|
|
129
|
+
typeof accessToken.expiresOn === 'string' ? new Date(accessToken.expiresOn) : accessToken.expiresOn
|
|
130
|
+
: new Date(0);
|
|
131
|
+
if (expiresOn < now) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
async ensureAccessToken(logger) {
|
|
137
|
+
try {
|
|
138
|
+
await auth.ensureAccessToken(auth.defaultResource, logger, this.debug);
|
|
139
|
+
auth.connection.active = true;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
if (this.debug) {
|
|
143
|
+
await logger.logToStderr('Error:');
|
|
144
|
+
await logger.logToStderr(error);
|
|
145
|
+
await logger.logToStderr('');
|
|
146
|
+
}
|
|
147
|
+
throw new CommandError(error.message);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
getCertificate(options) {
|
|
151
|
+
// command args take precedence over settings
|
|
152
|
+
if (options.certificateFile) {
|
|
153
|
+
return fs.readFileSync(options.certificateFile).toString('base64');
|
|
154
|
+
}
|
|
155
|
+
if (options.certificateBase64Encoded) {
|
|
156
|
+
return options.certificateBase64Encoded;
|
|
157
|
+
}
|
|
158
|
+
return cli.getConfig().get(settingsNames.clientCertificateFile) ||
|
|
159
|
+
cli.getConfig().get(settingsNames.clientCertificateBase64Encoded);
|
|
160
|
+
}
|
|
161
|
+
;
|
|
162
|
+
async login(logger, args) {
|
|
163
|
+
if (this.verbose) {
|
|
164
|
+
await logger.logToStderr(`Signing in to Microsoft 365...`);
|
|
165
|
+
}
|
|
166
|
+
const authType = args.options.authType || cli.getSettingWithDefaultValue(settingsNames.authType, 'deviceCode');
|
|
167
|
+
auth.connection.appId = args.options.appId || cli.getClientId();
|
|
168
|
+
auth.connection.tenant = args.options.tenant || cli.getTenant();
|
|
169
|
+
auth.connection.name = args.options.connectionName;
|
|
170
|
+
switch (authType) {
|
|
171
|
+
case 'password':
|
|
172
|
+
auth.connection.authType = AuthType.Password;
|
|
173
|
+
auth.connection.userName = args.options.userName;
|
|
174
|
+
auth.connection.password = args.options.password;
|
|
175
|
+
break;
|
|
176
|
+
case 'certificate':
|
|
177
|
+
auth.connection.authType = AuthType.Certificate;
|
|
178
|
+
auth.connection.certificate = this.getCertificate(args.options);
|
|
179
|
+
auth.connection.thumbprint = args.options.thumbprint;
|
|
180
|
+
auth.connection.password = args.options.password ?? cli.getConfig().get(settingsNames.clientCertificatePassword);
|
|
181
|
+
break;
|
|
182
|
+
case 'identity':
|
|
183
|
+
auth.connection.authType = AuthType.Identity;
|
|
184
|
+
auth.connection.userName = args.options.userName;
|
|
185
|
+
break;
|
|
186
|
+
case 'browser':
|
|
187
|
+
auth.connection.authType = AuthType.Browser;
|
|
188
|
+
break;
|
|
189
|
+
case 'secret':
|
|
190
|
+
auth.connection.authType = AuthType.Secret;
|
|
191
|
+
auth.connection.secret = args.options.secret || cli.getConfig().get(settingsNames.clientSecret);
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
auth.connection.cloudType = args.options.cloud;
|
|
195
|
+
await this.ensureAccessToken(logger);
|
|
196
|
+
const details = auth.getConnectionDetails(auth.connection);
|
|
197
|
+
if (this.debug) {
|
|
198
|
+
details.accessToken = JSON.stringify(auth.connection.accessTokens, null, 2);
|
|
199
|
+
}
|
|
200
|
+
await logger.log(details);
|
|
201
|
+
}
|
|
202
|
+
;
|
|
150
203
|
}
|
|
151
204
|
export default new LoginCommand();
|
|
152
205
|
//# sourceMappingURL=login.js.map
|
|
@@ -15,6 +15,9 @@ import { entraGroup } from '../../../../utils/entraGroup.js';
|
|
|
15
15
|
import aadCommands from '../../aadCommands.js';
|
|
16
16
|
import { accessToken } from '../../../../utils/accessToken.js';
|
|
17
17
|
import auth from '../../../../Auth.js';
|
|
18
|
+
import { entraUser } from '../../../../utils/entraUser.js';
|
|
19
|
+
import { formatting } from '../../../../utils/formatting.js';
|
|
20
|
+
import { odata } from '../../../../utils/odata.js';
|
|
18
21
|
class EntraM365GroupSetCommand extends GraphCommand {
|
|
19
22
|
get name() {
|
|
20
23
|
return commands.M365GROUP_SET;
|
|
@@ -102,59 +105,13 @@ class EntraM365GroupSetCommand extends GraphCommand {
|
|
|
102
105
|
else if (this.debug) {
|
|
103
106
|
await logger.logToStderr('logoPath not set. Skipping');
|
|
104
107
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
const requestOptions = {
|
|
111
|
-
url: `${this.resource}/v1.0/users?$filter=${owners.map(o => `userPrincipalName eq '${o}'`).join(' or ')}&$select=id`,
|
|
112
|
-
headers: {
|
|
113
|
-
'content-type': 'application/json'
|
|
114
|
-
},
|
|
115
|
-
responseType: 'json'
|
|
116
|
-
};
|
|
117
|
-
const res = await request.get(requestOptions);
|
|
118
|
-
await Promise.all(res.value.map(u => request.post({
|
|
119
|
-
url: `${this.resource}/v1.0/groups/${groupId}/owners/$ref`,
|
|
120
|
-
headers: {
|
|
121
|
-
'content-type': 'application/json'
|
|
122
|
-
},
|
|
123
|
-
responseType: 'json',
|
|
124
|
-
data: {
|
|
125
|
-
"@odata.id": `https://graph.microsoft.com/v1.0/users/${u.id}`
|
|
126
|
-
}
|
|
127
|
-
})));
|
|
128
|
-
}
|
|
129
|
-
else if (this.debug) {
|
|
130
|
-
await logger.logToStderr('Owners not set. Skipping');
|
|
131
|
-
}
|
|
132
|
-
if (args.options.members) {
|
|
133
|
-
const members = args.options.members.split(',').map(o => o.trim());
|
|
134
|
-
if (this.verbose) {
|
|
135
|
-
await logger.logToStderr('Retrieving user information to set group members...');
|
|
136
|
-
}
|
|
137
|
-
const requestOptions = {
|
|
138
|
-
url: `${this.resource}/v1.0/users?$filter=${members.map(o => `userPrincipalName eq '${o}'`).join(' or ')}&$select=id`,
|
|
139
|
-
headers: {
|
|
140
|
-
'content-type': 'application/json'
|
|
141
|
-
},
|
|
142
|
-
responseType: 'json'
|
|
143
|
-
};
|
|
144
|
-
const res = await request.get(requestOptions);
|
|
145
|
-
await Promise.all(res.value.map(u => request.post({
|
|
146
|
-
url: `${this.resource}/v1.0/groups/${groupId}/members/$ref`,
|
|
147
|
-
headers: {
|
|
148
|
-
'content-type': 'application/json'
|
|
149
|
-
},
|
|
150
|
-
responseType: 'json',
|
|
151
|
-
data: {
|
|
152
|
-
"@odata.id": `https://graph.microsoft.com/v1.0/users/${u.id}`
|
|
153
|
-
}
|
|
154
|
-
})));
|
|
108
|
+
const ownerIds = await this.getUserIds(logger, args.options.ownerIds, args.options.ownerUserNames);
|
|
109
|
+
const memberIds = await this.getUserIds(logger, args.options.memberIds, args.options.memberUserNames);
|
|
110
|
+
if (ownerIds.length > 0) {
|
|
111
|
+
await this.updateUsers(logger, groupId, 'owners', ownerIds);
|
|
155
112
|
}
|
|
156
|
-
|
|
157
|
-
await
|
|
113
|
+
if (memberIds.length > 0) {
|
|
114
|
+
await this.updateUsers(logger, groupId, 'members', memberIds);
|
|
158
115
|
}
|
|
159
116
|
}
|
|
160
117
|
catch (err) {
|
|
@@ -186,6 +143,87 @@ class EntraM365GroupSetCommand extends GraphCommand {
|
|
|
186
143
|
return 'image/jpeg';
|
|
187
144
|
}
|
|
188
145
|
}
|
|
146
|
+
async getUserIds(logger, userIds, userNames) {
|
|
147
|
+
if (userIds) {
|
|
148
|
+
return formatting.splitAndTrim(userIds);
|
|
149
|
+
}
|
|
150
|
+
if (userNames) {
|
|
151
|
+
if (this.verbose) {
|
|
152
|
+
await logger.logToStderr(`Retrieving user IDs...`);
|
|
153
|
+
}
|
|
154
|
+
return entraUser.getUserIdsByUpns(formatting.splitAndTrim(userNames));
|
|
155
|
+
}
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
async updateUsers(logger, groupId, role, userIds) {
|
|
159
|
+
const groupUsers = await odata.getAllItems(`${this.resource}/v1.0/groups/${groupId}/${role}/microsoft.graph.user?$select=id`);
|
|
160
|
+
const userIdsToAdd = userIds.filter(userId => !groupUsers.some(groupUser => groupUser.id === userId));
|
|
161
|
+
const userIdsToRemove = groupUsers.filter(groupUser => !userIds.some(userId => groupUser.id === userId)).map(user => user.id);
|
|
162
|
+
if (this.verbose) {
|
|
163
|
+
await logger.logToStderr(`Adding ${userIdsToAdd.length} ${role}...`);
|
|
164
|
+
}
|
|
165
|
+
for (let i = 0; i < userIdsToAdd.length; i += 400) {
|
|
166
|
+
const userIdsBatch = userIdsToAdd.slice(i, i + 400);
|
|
167
|
+
const batchRequestOptions = this.getBatchRequestOptions();
|
|
168
|
+
// only 20 requests per one batch are allowed
|
|
169
|
+
for (let j = 0; j < userIdsBatch.length; j += 20) {
|
|
170
|
+
// only 20 users can be added in one request
|
|
171
|
+
const userIdsChunk = userIdsBatch.slice(j, j + 20);
|
|
172
|
+
batchRequestOptions.data.requests.push({
|
|
173
|
+
id: j + 1,
|
|
174
|
+
method: 'PATCH',
|
|
175
|
+
url: `/groups/${groupId}`,
|
|
176
|
+
headers: {
|
|
177
|
+
'content-type': 'application/json;odata.metadata=none',
|
|
178
|
+
accept: 'application/json;odata.metadata=none'
|
|
179
|
+
},
|
|
180
|
+
body: {
|
|
181
|
+
[`${role}@odata.bind`]: userIdsChunk.map(u => `${this.resource}/v1.0/directoryObjects/${u}`)
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const res = await request.post(batchRequestOptions);
|
|
186
|
+
for (const response of res.responses) {
|
|
187
|
+
if (response.status !== 204) {
|
|
188
|
+
throw response.body;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (this.verbose) {
|
|
193
|
+
await logger.logToStderr(`Removing ${userIdsToRemove.length} ${role}...`);
|
|
194
|
+
}
|
|
195
|
+
for (let i = 0; i < userIdsToRemove.length; i += 20) {
|
|
196
|
+
const userIdsBatch = userIdsToRemove.slice(i, i + 20);
|
|
197
|
+
const batchRequestOptions = this.getBatchRequestOptions();
|
|
198
|
+
userIdsBatch.map(userId => {
|
|
199
|
+
batchRequestOptions.data.requests.push({
|
|
200
|
+
id: userId,
|
|
201
|
+
method: 'DELETE',
|
|
202
|
+
url: `/groups/${groupId}/${role}/${userId}/$ref`
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
const res = await request.post(batchRequestOptions);
|
|
206
|
+
for (const response of res.responses) {
|
|
207
|
+
if (response.status !== 204) {
|
|
208
|
+
throw response.body;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
getBatchRequestOptions() {
|
|
214
|
+
const requestOptions = {
|
|
215
|
+
url: `${this.resource}/v1.0/$batch`,
|
|
216
|
+
headers: {
|
|
217
|
+
'content-type': 'application/json;odata.metadata=none',
|
|
218
|
+
accept: 'application/json;odata.metadata=none'
|
|
219
|
+
},
|
|
220
|
+
responseType: 'json',
|
|
221
|
+
data: {
|
|
222
|
+
requests: []
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
return requestOptions;
|
|
226
|
+
}
|
|
189
227
|
}
|
|
190
228
|
_EntraM365GroupSetCommand_instances = new WeakSet(), _EntraM365GroupSetCommand_initTelemetry = function _EntraM365GroupSetCommand_initTelemetry() {
|
|
191
229
|
this.telemetry.push((args) => {
|
|
@@ -194,8 +232,10 @@ _EntraM365GroupSetCommand_instances = new WeakSet(), _EntraM365GroupSetCommand_i
|
|
|
194
232
|
displayName: typeof args.options.displayName !== 'undefined',
|
|
195
233
|
newDisplayName: typeof args.options.newDisplayName !== 'undefined',
|
|
196
234
|
description: typeof args.options.description !== 'undefined',
|
|
197
|
-
|
|
198
|
-
|
|
235
|
+
ownerIds: typeof args.options.ownerIds !== 'undefined',
|
|
236
|
+
ownerUserNames: typeof args.options.ownerUserNames !== 'undefined',
|
|
237
|
+
memberIds: typeof args.options.memberIds !== 'undefined',
|
|
238
|
+
memberUserNames: typeof args.options.memberUserNames !== 'undefined',
|
|
199
239
|
isPrivate: !!args.options.isPrivate,
|
|
200
240
|
logoPath: typeof args.options.logoPath !== 'undefined',
|
|
201
241
|
allowExternalSenders: !!args.options.allowExternalSenders,
|
|
@@ -214,9 +254,13 @@ _EntraM365GroupSetCommand_instances = new WeakSet(), _EntraM365GroupSetCommand_i
|
|
|
214
254
|
}, {
|
|
215
255
|
option: '-d, --description [description]'
|
|
216
256
|
}, {
|
|
217
|
-
option: '--
|
|
257
|
+
option: '--ownerIds [ownerIds]'
|
|
258
|
+
}, {
|
|
259
|
+
option: '--ownerUserNames [ownerUserNames]'
|
|
218
260
|
}, {
|
|
219
|
-
option: '--
|
|
261
|
+
option: '--memberIds [memberIds]'
|
|
262
|
+
}, {
|
|
263
|
+
option: '--memberUserNames [memberUserNames]'
|
|
220
264
|
}, {
|
|
221
265
|
option: '--isPrivate [isPrivate]',
|
|
222
266
|
autocomplete: ['true', 'false']
|
|
@@ -237,17 +281,31 @@ _EntraM365GroupSetCommand_instances = new WeakSet(), _EntraM365GroupSetCommand_i
|
|
|
237
281
|
});
|
|
238
282
|
}, _EntraM365GroupSetCommand_initOptionSets = function _EntraM365GroupSetCommand_initOptionSets() {
|
|
239
283
|
this.optionSets.push({ options: ['id', 'displayName'] });
|
|
284
|
+
this.optionSets.push({
|
|
285
|
+
options: ['ownerIds', 'ownerUserNames'],
|
|
286
|
+
runsWhen: (args) => {
|
|
287
|
+
return args.options.ownerIds !== undefined || args.options.ownerUserNames !== undefined;
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
this.optionSets.push({
|
|
291
|
+
options: ['memberIds', 'memberUserNames'],
|
|
292
|
+
runsWhen: (args) => {
|
|
293
|
+
return args.options.memberIds !== undefined || args.options.memberUserNames !== undefined;
|
|
294
|
+
}
|
|
295
|
+
});
|
|
240
296
|
}, _EntraM365GroupSetCommand_initTypes = function _EntraM365GroupSetCommand_initTypes() {
|
|
241
297
|
this.types.boolean.push('isPrivate', 'allowEternalSenders', 'autoSubscribeNewMembers', 'hideFromAddressLists', 'hideFromOutlookClients');
|
|
242
|
-
this.types.string.push('id', 'displayName', 'newDisplayName', 'description', '
|
|
298
|
+
this.types.string.push('id', 'displayName', 'newDisplayName', 'description', 'ownerIds', 'ownerUserNames', 'memberIds', 'memberUserNames', 'logoPath');
|
|
243
299
|
}, _EntraM365GroupSetCommand_initValidators = function _EntraM365GroupSetCommand_initValidators() {
|
|
244
300
|
this.validators.push(async (args) => {
|
|
245
301
|
if (!args.options.newDisplayName &&
|
|
246
302
|
args.options.description === undefined &&
|
|
247
|
-
|
|
248
|
-
|
|
303
|
+
args.options.ownerIds === undefined &&
|
|
304
|
+
args.options.ownerUserNames === undefined &&
|
|
305
|
+
args.options.memberIds === undefined &&
|
|
306
|
+
args.options.memberUserNames === undefined &&
|
|
249
307
|
args.options.isPrivate === undefined &&
|
|
250
|
-
|
|
308
|
+
args.options.logoPath === undefined &&
|
|
251
309
|
args.options.allowExternalSenders === undefined &&
|
|
252
310
|
args.options.autoSubscribeNewMembers === undefined &&
|
|
253
311
|
args.options.hideFromAddressLists === undefined &&
|
|
@@ -257,16 +315,28 @@ _EntraM365GroupSetCommand_instances = new WeakSet(), _EntraM365GroupSetCommand_i
|
|
|
257
315
|
if (args.options.id && !validation.isValidGuid(args.options.id)) {
|
|
258
316
|
return `${args.options.id} is not a valid GUID`;
|
|
259
317
|
}
|
|
260
|
-
if (args.options.
|
|
261
|
-
const
|
|
262
|
-
if (
|
|
263
|
-
return `
|
|
318
|
+
if (args.options.ownerIds) {
|
|
319
|
+
const isValidGUIDArrayResult = validation.isValidGuidArray(args.options.ownerIds);
|
|
320
|
+
if (isValidGUIDArrayResult !== true) {
|
|
321
|
+
return `The following GUIDs are invalid for the option 'ownerIds': ${isValidGUIDArrayResult}.`;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (args.options.ownerUserNames) {
|
|
325
|
+
const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.ownerUserNames);
|
|
326
|
+
if (isValidUPNArrayResult !== true) {
|
|
327
|
+
return `The following user principal names are invalid for the option 'ownerUserNames': ${isValidUPNArrayResult}.`;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (args.options.memberIds) {
|
|
331
|
+
const isValidGUIDArrayResult = validation.isValidGuidArray(args.options.memberIds);
|
|
332
|
+
if (isValidGUIDArrayResult !== true) {
|
|
333
|
+
return `The following GUIDs are invalid for the option 'memberIds': ${isValidGUIDArrayResult}.`;
|
|
264
334
|
}
|
|
265
335
|
}
|
|
266
|
-
if (args.options.
|
|
267
|
-
const
|
|
268
|
-
if (
|
|
269
|
-
return `
|
|
336
|
+
if (args.options.memberUserNames) {
|
|
337
|
+
const isValidUPNArrayResult = validation.isValidUserPrincipalNameArray(args.options.memberUserNames);
|
|
338
|
+
if (isValidUPNArrayResult !== true) {
|
|
339
|
+
return `The following user principal names are invalid for the option 'memberUserNames': ${isValidUPNArrayResult}.`;
|
|
270
340
|
}
|
|
271
341
|
}
|
|
272
342
|
if (args.options.logoPath) {
|
|
@@ -20,28 +20,34 @@ m365 aad m365group set [options]
|
|
|
20
20
|
|
|
21
21
|
```md definition-list
|
|
22
22
|
`-i, --id [id]`
|
|
23
|
-
: The ID of the Microsoft 365 Group to update
|
|
23
|
+
: The ID of the Microsoft 365 Group to update.
|
|
24
24
|
|
|
25
25
|
`-n, --displayName [displayName]`
|
|
26
|
-
: Display name of the Microsoft 365 Group to update
|
|
26
|
+
: Display name of the Microsoft 365 Group to update.
|
|
27
27
|
|
|
28
28
|
`--newDisplayName [newDisplayName]`
|
|
29
|
-
: New display name for the Microsoft 365 Group
|
|
29
|
+
: New display name for the Microsoft 365 Group.
|
|
30
30
|
|
|
31
31
|
`-d, --description [description]`
|
|
32
|
-
: Description for the Microsoft 365 Group
|
|
32
|
+
: Description for the Microsoft 365 Group.
|
|
33
33
|
|
|
34
|
-
`--
|
|
35
|
-
: Comma-separated list of Microsoft
|
|
34
|
+
`--ownerIds [ownerIds]`
|
|
35
|
+
: Comma-separated list of IDs of Microsoft Entra ID users that will be group owners. Specify either `ownerIds` or `ownerUserNames`, but not both.
|
|
36
36
|
|
|
37
|
-
`--
|
|
38
|
-
: Comma-separated list of Microsoft
|
|
37
|
+
`--ownerUserNames [ownerUserNames]`
|
|
38
|
+
: Comma-separated list of UPNs of Microsoft Entra ID users that will be group owners. Specify either `ownerIds` or `ownerUserNames`, but not both.
|
|
39
|
+
|
|
40
|
+
`--memberIds [memberIds]`
|
|
41
|
+
: Comma-separated list of IDs of Microsoft Entra ID users that will be group members. Specify either `memberIds` or `memberUserNames`, but not both.
|
|
42
|
+
|
|
43
|
+
`--memberUserNames [memberUserNames]`
|
|
44
|
+
: Comma-separated list of UPNs of Microsoft Entra ID users that will be group members. Specify either `memberIds` or `memberUserNames`, but not both.
|
|
39
45
|
|
|
40
46
|
`--isPrivate [isPrivate]`
|
|
41
47
|
: Set to `true` if the Microsoft 365 Group should be private and `false` if it should be public.
|
|
42
48
|
|
|
43
49
|
`-l, --logoPath [logoPath]`
|
|
44
|
-
: Local path to the image file to use as group logo
|
|
50
|
+
: Local path to the image file to use as group logo.
|
|
45
51
|
|
|
46
52
|
`--allowExternalSenders [allowExternalSenders]`
|
|
47
53
|
: Indicates if people external to the organization can send messages to the group. Valid values: `true`, `false`.
|
|
@@ -60,7 +66,7 @@ m365 aad m365group set [options]
|
|
|
60
66
|
|
|
61
67
|
## Remarks
|
|
62
68
|
|
|
63
|
-
When updating group's owners and members, the command will
|
|
69
|
+
When updating group's owners and members, the command will remove existing owners/members from the group, and the specified users will be added.
|
|
64
70
|
|
|
65
71
|
When specifying the path to the logo image you can use both relative and absolute paths. Note, that ~ in the path, will not be resolved and will most likely result in an error.
|
|
66
72
|
|
|
@@ -84,16 +90,28 @@ Change Microsoft 365 Group visibility to public.
|
|
|
84
90
|
m365 entra m365group set --id 28beab62-7540-4db1-a23f-29a6018a3848 --isPrivate `false`
|
|
85
91
|
```
|
|
86
92
|
|
|
87
|
-
|
|
93
|
+
Updates the list of Microsoft 365 Group owners with a list of users by UPN.
|
|
94
|
+
|
|
95
|
+
```sh
|
|
96
|
+
m365 entra m365group set --id 28beab62-7540-4db1-a23f-29a6018a3848 --ownerUserNames "DebraB@contoso.onmicrosoft.com,DiegoS@contoso.onmicrosoft.com"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Updates the list of Microsoft 365 Group owners with a list of users by ID.
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
m365 entra m365group set --id 28beab62-7540-4db1-a23f-29a6018a3848 --ownerIds "3527dada-9368-4cdd-a958-5460f5658e0e,e94b2cb8-7c9a-4651-b1af-207d81a010b6"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Updates the list of Microsoft 365 Group members with a list of users by UPN.
|
|
88
106
|
|
|
89
107
|
```sh
|
|
90
|
-
m365 entra m365group set --
|
|
108
|
+
m365 entra m365group set --id 28beab62-7540-4db1-a23f-29a6018a3848 --memberUserNames "DebraB@contoso.onmicrosoft.com,DiegoS@contoso.onmicrosoft.com"
|
|
91
109
|
```
|
|
92
110
|
|
|
93
|
-
|
|
111
|
+
Updates the list of Microsoft 365 Group members with a list of users by ID.
|
|
94
112
|
|
|
95
113
|
```sh
|
|
96
|
-
m365 entra m365group set --
|
|
114
|
+
m365 entra m365group set --id 28beab62-7540-4db1-a23f-29a6018a3848 --memberIds "3527dada-9368-4cdd-a958-5460f5658e0e,e94b2cb8-7c9a-4651-b1af-207d81a010b6"
|
|
97
115
|
```
|
|
98
116
|
|
|
99
117
|
Update Microsoft 365 Group logo.
|
|
@@ -116,4 +134,4 @@ m365 entra m365group set --id 28beab62-7540-4db1-a23f-29a6018a3848 --autoSubscri
|
|
|
116
134
|
|
|
117
135
|
## Response
|
|
118
136
|
|
|
119
|
-
The command won't return a response on success.
|
|
137
|
+
The command won't return a response on success.
|
package/docs/docs/cmd/login.mdx
CHANGED
|
@@ -47,6 +47,9 @@ m365 login [options]
|
|
|
47
47
|
|
|
48
48
|
`--connectionName [connectionName]`
|
|
49
49
|
: Specify an optional name to make switching between connections easier.
|
|
50
|
+
|
|
51
|
+
`--ensure`
|
|
52
|
+
: Ensures that the user is signed in. if the user isn't signed in, it initiates the login flow
|
|
50
53
|
```
|
|
51
54
|
|
|
52
55
|
<Global />
|
|
@@ -190,6 +193,12 @@ Log in to Microsoft 365 using a client secret.
|
|
|
190
193
|
m365 login --authType secret --secret topSeCr3t@007
|
|
191
194
|
```
|
|
192
195
|
|
|
196
|
+
Ensures that the user is signed in, initiates the login flow if the user isn't signed in
|
|
197
|
+
|
|
198
|
+
```sh
|
|
199
|
+
m365 login --ensure
|
|
200
|
+
```
|
|
201
|
+
|
|
193
202
|
## Response
|
|
194
203
|
|
|
195
204
|
<Tabs>
|
package/package.json
CHANGED