Desired Behaviour
Create a Microsoft Team, with specified Owners and Members, in a Power Automate Flow using the HTTP connector to make requests to the Microsoft Graph API.
Actual Behaviour
This code shows how you can create a Microsoft Team whilst specifying it's Owners by User ID.
{
"template#odata.bind": "https://graph.microsoft.com/v1.0/teamsTemplates('standard')",
"displayName": "My Sample Team",
"description": "My Sample Team’s Description",
"members": [
{
"#odata.type": "#microsoft.graph.aadUserConversationMember",
"roles": [
"owner"
],
"user#odata.bind": "https://graph.microsoft.com/v1.0/users('0040b377-61d8-43db-94f5-81374122dc7e')"
}]
}
Source
For reference, the Graph API docs entry for Get a user (which is used to specify the Owner in the code above), specifies the endpoint syntax as:
GET /users/{id | userPrincipalName}
Currently, I do not have access to users' id or userPrincipalName.
What I've Tried
I am using a Power Automate Flow with the SharePoint For a selected item trigger.
The list includes two columns of type Person where Owners and Members are specified.
In order to get a list of Owners, I am using the SharePoint connector's Get item action on the selected item and then using an Apply to each control to iterate over each columns' values.
Below is the Raw Output of Get Item - the Owners column array is TeamOwner_x002f_s.
You can see that each object only has DisplayName and Email and not User ID or userPrincipalName:
{
"statusCode": 200,
"headers": {
"Transfer-Encoding": "chunked",
"Vary": "Origin,Accept-Encoding",
"X-SharePointHealthScore": "1",
"X-MS-SPConnector": "1",
"X-SP-SERVERSTATE": "ReadOnly=0",
"DATASERVICEVERSION": "3.0",
"SPClientServiceRequestDuration": "68",
"SPRequestGuid": "letters-and-numbers",
"request-id": "letters-and-numbers",
"MS-CV": "letters-and-numbers.0",
"Strict-Transport-Security": "max-age=31536000",
"X-FRAME-OPTIONS": "SAMEORIGIN",
"Content-Security-Policy": "frame-ancestors 'self' teams.microsoft.com *.teams.microsoft.com *.skype.com *.teams.microsoft.us local.teams.office.com *.powerapps.com *.yammer.com *.officeapps.live.com *.office.com *.stream.azure-test.net *.microsoftstream.com;",
"MicrosoftSharePointTeamServices": "numbers-and-dots",
"X-Content-Type-Options": "nosniff",
"X-MS-InvokeApp": "1; RequireReadOnly",
"Timing-Allow-Origin": "*",
"x-ms-apihub-cached-response": "false",
"Cache-Control": "max-age=0, private",
"Date": "Sun, 04 Jul 2021 06:42:53 GMT",
"P3P": "CP=\"SOME CODES HERE\"",
"X-AspNet-Version": "4.0.30319",
"X-Powered-By": "ASP.NET",
"Content-Type": "application/json; charset=utf-8",
"Expires": "Sat, 19 Jun 2021 06:42:54 GMT",
"Last-Modified": "Sun, 04 Jul 2021 06:42:54 GMT",
"Content-Length": "3938"
},
"body": {
"#odata.etag": "\"2\"",
"ItemInternalId": "1",
"ID": 1,
"Title": "View",
"Year": {
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference",
"Id": 2,
"Value": "2023"
},
"Year#Id": 2,
"ProgramType": {
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference",
"Id": 0,
"Value": "Program Type 01"
},
"ProgramType#Id": 0,
"ProgramName": {
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference",
"Id": 1,
"Value": "02"
},
"ProgramName#Id": 1,
"TeamOwner_x002f_s": [
{
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
"Claims": "i:0#.f|membership|user_1#my-tenant.onmicrosoft.com",
"DisplayName": "User Name 1",
"Email": "user_1#my-tenant.onmicrosoft.com",
"Picture": "https://my-tenant.sharepoint.com/sites/ExampleTeam/_layouts/15/UserPhoto.aspx?Size=L&AccountName=user_1#my-tenant.onmicrosoft.com",
"Department": null,
"JobTitle": null
},
{
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
"Claims": "i:0#.f|membership|user_2#my-tenant.onmicrosoft.com",
"DisplayName": "User Name 2",
"Email": "user_2#my-tenant.onmicrosoft.com",
"Picture": "https://my-tenant.sharepoint.com/sites/ExampleTeam/_layouts/15/UserPhoto.aspx?Size=L&AccountName=user_2#my-tenant.onmicrosoft.com",
"Department": null,
"JobTitle": null
}
],
"TeamOwner_x002f_s#odata.type": "#Collection(Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser)",
"TeamOwner_x002f_s#Claims": [
"i:0#.f|membership|user_1#my-tenant.onmicrosoft.com",
"i:0#.f|membership|user_2#my-tenant.onmicrosoft.com"
],
"TeamOwner_x002f_s#Claims#odata.type": "#Collection(String)",
"Team_x0020_Member_x002f_s": [
{
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
"Claims": "i:0#.f|membership|user_3#my-tenant.onmicrosoft.com",
"DisplayName": "User Name 3",
"Email": "user_3#my-tenant.onmicrosoft.com",
"Picture": "https://my-tenant.sharepoint.com/sites/ExampleTeam/_layouts/15/UserPhoto.aspx?Size=L&AccountName=user_3#my-tenant.onmicrosoft.com",
"Department": null,
"JobTitle": null
}
],
"Team_x0020_Member_x002f_s#odata.type": "#Collection(Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser)",
"Team_x0020_Member_x002f_s#Claims": [
"i:0#.f|membership|user_3#my-tenant.onmicrosoft.com"
],
"Team_x0020_Member_x002f_s#Claims#odata.type": "#Collection(String)",
"Status": {
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedReference",
"Id": 0,
"Value": "Details Added"
},
"Status#Id": 0,
"Modified": "2021-07-04T03:57:16Z",
"Created": "2021-07-04T03:51:18Z",
"Author": {
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
"Claims": "i:0#.f|membership|user_1#my-tenant.onmicrosoft.com",
"DisplayName": "User Name 1",
"Email": "user_1#my-tenant.onmicrosoft.com",
"Picture": "https://my-tenant.sharepoint.com/sites/ExampleTeam/_layouts/15/UserPhoto.aspx?Size=L&AccountName=user_1#my-tenant.onmicrosoft.com",
"Department": null,
"JobTitle": null
},
"Author#Claims": "i:0#.f|membership|user_1#my-tenant.onmicrosoft.com",
"Editor": {
"#odata.type": "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
"Claims": "i:0#.f|membership|user_1#my-tenant.onmicrosoft.com",
"DisplayName": "User Name 1",
"Email": "user_1#my-tenant.onmicrosoft.com",
"Picture": "https://my-tenant.sharepoint.com/sites/ExampleTeam/_layouts/15/UserPhoto.aspx?Size=L&AccountName=user_1#my-tenant.onmicrosoft.com",
"Department": null,
"JobTitle": null
},
"Editor#Claims": "i:0#.f|membership|user_1#my-tenant.onmicrosoft.com",
"{Identifier}": "Lists%252fMy%2bList%2bName%252f1_.000",
"{IsFolder}": false,
"{Thumbnail}": {
"Large": null,
"Medium": null,
"Small": null
},
"{Link}": "https://my-tenant.sharepoint.com/sites/ExampleTeam/_layouts/15/listform.aspx?PageType=4&ListId=list-id-here&ID=1&ContentTypeID=content-type-id-here",
"{Name}": "View",
"{FilenameWithExtension}": "View",
"{Path}": "Lists/My List Name/",
"{FullPath}": "Lists/My List Name/1_.000",
"{VersionNumber}": "2.0"
}
}
Question
Is it possible to specify Team members by Email in the Graph API request?
Or do I need to somehow get the User ID of each user specified (and if so, what is the best way to do that)?
Update
I tried this HTTP connector GET request in the hopes it would return User ID for each Person:
https://graph.microsoft.com/v1.0/sites/site-id-here/lists/list-id-here/items/item-id-here?expand=fields(select=TeamOwner%5Fx002f%5Fs)
But it returned even less information:
"fields": {
"#odata.etag": "\"letters-and-numbers,2\"",
"TeamOwner_x002f_s": [{
"LookupId": 9,
"LookupValue": "User Name 1",
"Email": "user_1#my-tenant.onmicrosoft.com"
},
{
"LookupId": 27,
"LookupValue": "User Name 2",
"Email": "user_2#my-tenant.onmicrosoft.com"
}
]
}
API docs reference for this approach
Get specific column values of a listItem
GET https://graph.microsoft.com/v1.0/sites/{site-id}/lists/{list-id}/items/{item-id}?expand=fields(select=Column1,Column2)
You can get the user information from Microsoft Graph itself, what you can try out is List Users with filter parameter.
like this:
GET https://graph.microsoft.com/v1.0/users?$filter(mail eq 'user_1#my-tenant.onmicrosoft.com')
OR
You can list all users and do a mail/displayName search(Ctrl+F) on results at graph explorer.
By these you will be able to get userPrincipalName as well as id.
Permission required:-
One of the following permissions is required to call this API.
Delegated (work or school account) - User.ReadBasic.All,
User.Read.All, User.ReadWrite.All, Directory.Read.All,
Directory.ReadWrite.All, Directory.AccessAsUser.All
Delegated
(personal Microsoft account) - Not supported.
Application - User.Read.All, User.ReadWrite.All, Directory.Read.All,
Directory.ReadWrite.All
Thanks.
When setting the permission / access link in OneDrive, there is quite a few options:
But when accessing the file permission using Microsoft Graph API
https://graph.microsoft.com/v1.0/users/{user_id}/drive/items/{item_id}/permissions
I do not get the set expiration date, set password or block download:
the response looks like this:
{
"id": "permission_id",
"roles": [
"write"
],
"link": {
"scope": "anonymous",
"type": "edit",
"webUrl": "webUrl"
}
}
How can I get all the data? Should I use a different API?
Seems like beta version of Graph API supports this:
https://graph.microsoft.com/beta/users/{user_id}/drive/items/{item_id}/permissions/{permission_id}
will give the following response:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#users('user_id')/drive/items('item_id')/permissions/$entity",
"expirationDateTime": "2020-04-26T21:00:00Z",
"hasPassword": true,
"id": "permission_id",
"roles": [
"read"
],
"link": {
"preventsDownload": true,
"scope": "anonymous",
"type": "view",
"webUrl": "webUrl"
}
}
When reviewing some example OneDrive Items using Graph Explorer, it appears that the user.id and the parentReference.driveId are identical. Is MSFT re-using one Id to identify both the user and drive object?
I have been testing my app against a number of OneDrive Business accounts and I do not believe I have seen this scenario. I would like to understand if this is something specific to OneDrive Personal and/or what implications it might have...
I am not sure this will cause any issues, but my understanding was that all "IDs" were generally unique.
Here's a redacted snippet of JSON returned from Graph Explorer to illustrate what I am seeing:
{
"#microsoft.graph.downloadUrl": "https://xxx.yyy",
"createdDateTime": "2018-12-04T19:02:41.173Z",
"cTag": "aYzpDQjBCMTc0REJFRUY2RTU4ITMxNzEuMjI1",
"eTag": "aQ0IwQjE3NERCRUVGNkU1OCEzMTcxLjk",
"id": "<MY_USER_ID>!3171",
"lastModifiedDateTime": "2018-12-04T19:10:36.83Z",
"name": "blah-2018.docx",
"size": 250538,
"webUrl": "https://1drv.ms/...",
"createdBy": {
"application": {
"displayName": "MSOffice15",
"id": "480728c5"
},
"device": {
"id": "188000899fbcaf"
},
"user": {
"displayName": "My Name",
"id": "<MY_USER_ID>"
}
},
"lastModifiedBy": {
"application": {
"displayName": "MSOffice15",
"id": "480728c5"
},
"device": {
"id": "188000899fbcaf"
},
"user": {
"displayName": "My Name",
"id": "<MY_USER_ID>"
}
},
"parentReference": {
"driveId": "<MY_USER_ID>",
"driveType": "personal",
"id": "<MY_USER_ID>!109",
"path": "/drive/root:"
},
"file": {
"mimeType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"hashes": {
"sha1Hash": "F0370F54348ED81F421EB036868AEBE5253AF58A"
}
},
"fileSystemInfo": {
"createdDateTime": "2018-12-04T19:02:41.173Z",
"lastModifiedDateTime": "2018-12-04T19:02:38.633Z"
}
},
Note that MY_USER_ID is all uppercase in the prefix of the driveItem.Id. It is all lowercase as my driveId and my userId.
OneDrive Personal isn't reusing the same id, it's using the User's Id as a prefix for Drive and DriveItem ids:
{User Id}!{OneDrive ID}
Since there is a 1:1 relationship between an MSA and it's Drive, there isn't much call for a more complex mechanism. OneDrive for Business, on the other hand, is hosted in SharePoint and, as such, use's SharePoint's identifiers.
`
Using the MS Graph REST API, I can retrieve driveItems that are shared with me. The Permissions of those "remote" driveItems include one identifying me as a user. However, that Permission object has no "Roles" in it (specifically, the Roles list has zero entries).
I tried looking at the RemoteItem properties, but these do not contain any security info.
What is the correct method to determine what my user's permissions are on that specific DriveItem?
Thus far, I have tested using the C# MSGraph SDK and found all the items shared with me to have an empty Roles list.
I have also used the online Graph Explorer and determined the same to be true.
When I retrieved the actual item using Graph Explorer, note the following in this example snippet from MSFT:
{
"id": "aTowIy5mfG1lbWJlcnNoaXB8YWxleHdAbTM2NXgyMTQzNTUub25taWNyb3NvZnQuY29t",
"roles": [],
"grantedTo": {
"user": {
"email": "AlexW#M365x214355.onmicrosoft.com",
"id": "4782e723-f4f4-4af3-a76e-25e3bab0d896",
"displayName": "Alex Wilber"
}
}
},
(No roles are listed for the user?)
I would have expected, since my User was explicitly listed in one of the Permits of the actual DriveItem retrieved, that the Role would also have specified my access/actual permission.
The following endpoint:
GET /drives/{remoteItem-driveId}/items/{remoteItem-id}/permissions
returns sharing permissions on a DriveItem resource
Result
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#drives('b%21IZJbPb0BjUKDAjMnMOSRf44bwdRO75NGunQibG16o65AcVUi0kiOSZ9k4-NxVd6C')/items('01H24BBVK3QUEPTCR2MNB3HMLTNUZINN54')/permissions",
"value": [
{
"id": "c0594808-fbbb-4c56-9b62-bc37307a2424",
"roles": [
"write"
],
"link": {
"scope": "anonymous",
"type": "edit",
"webUrl": "https://contoso-my.sharepoint.com/:w:/g/personal/jdoe_contoso_onmicrosoft_com/EVuFCPmKOmNDs7FzbTKGt7wBxdHHpbjDMOzy3_ng2KHCAQ"
}
},
{
"id": "8a03ff0b-5196-4585-b8a9-4d95115e10c2",
"roles": [
"read"
],
"link": {
"scope": "anonymous",
"type": "view",
"webUrl": "https://contoso-my.sharepoint.com/:w:/g/personal/jdoe_contoso_onmicrosoft_com/EVuFCPmKOmNDs7FzbTKGt7wB8wPZsfAqSd-IQYE337GDjg"
}
},
{
"id": "aTowIy5mfG1lbWJlcnNoaXB8dmdyZW1AbWVkaWFkZXY4OC5vbm1pY3Jvc29mdC5jb20",
"roles": [
"owner"
],
"grantedTo": {
"user": {
"email": "jdoe#contoso.onmicrosoft.com",
"id": "1ee49b6f-4632-4806-a4dd-e065844f9cd1",
"displayName": "Jon Doe"
}
}
}
]
}
The following example demonstrates how to print Permissions resource Roles property via msgraph-sdk-dotnet:
var item = await graphClient.Drives[driveId].Items[itemId].Request().Expand("Permissions").GetAsync();
foreach (var permission in item.Permissions)
{
var roleNames = String.Join(", ", permission.Roles.ToArray());
Console.WriteLine(roleNames);
}
I have been trying to grant a single user (possibly outside of the organization) access to a folder used by a shared group in Share Point The Microsoft Graph Docs state that the response should have an Id in it.
If I use a personal oneDrive account, and make the following request:
POST v1.0
https://graph.microsoft.com/v1.0/groups/{groupId}/drive/items/{folderId}/invite
body: {
"requireSignIn": true,
"sendInvitation": true,
"roles": [ "read"],
"recipients": [
{ "email": "{myPersonalEmail}" },
],
"message": "testing giving permission to self"
}
I get the following response:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(permission)",
"value": [
{
"#odata.type": "#microsoft.graph.permission",
"id": "{permissionID}",
"roles": [
"read"
],
"grantedTo": {
"user": {
"email": "{myPersonalEmail}",
"id": "{responseID}",
"displayName": "Sarah"
}
}
}
]
}
However, we setup a different SharePoint account that when I make the same request https://graph.microsoft.com/v1.0/groups/{groupId}/drive/items/{folderId}/invite
I get a completely different response:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#Collection(permission)",
"value": [
{
"#odata.type": "#microsoft.graph.permission",
"roles": [
"read"
],
"invitation": {
"signInRequired": true
},
"link": {
"type": "view",
"webUrl": "{shareURL}"
}
}
]
}
This is so bizarre to me, because we are hitting the same endpoint. It makes me think that maybe there are some site configurations that are making these two responses differ.
Does anyone know why we would be getting a different results from the same endpoint?