diff --git a/Research_Notes/Microsoft-Graph-Behavior.md b/Research_Notes/Microsoft-Graph-Behavior.md index c7b8b2b..f4eedfa 100644 --- a/Research_Notes/Microsoft-Graph-Behavior.md +++ b/Research_Notes/Microsoft-Graph-Behavior.md @@ -2,13 +2,15 @@ What Microsoft Graph and the Microsoft Graph PowerShell SDK do in the areas this module relies on: permissions, what a successful send returns, chat creation and reuse, attachment and upload limits, how SDK sign-in -persists, and what disconnecting after a send changes. Each claim is tied to the part of the module it affects. +persists, what disconnecting after a send changes, and which forms of address find a user. Each claim is tied to +the part of the module it affects. -**Only sections 7 and 9 were measured against a tenant**, on **2026-09-16** and **2026-09-30**; each section -gives its environment. Documentation was read on **2026-09-15** from the pages listed under Sources, and the SDK -source on **2026-09-16**, except for section 8, whose pages and SDK source were read on **2026-09-21**, and -section 9, whose pages were read on **2026-09-30**. Microsoft revises these pages, so re-read a page before -relying on a limit or a permission. +**Only sections 7, 9, and 10, and one finding in section 5, were measured against a tenant**, on **2026-09-16**, +**2026-09-30**, **2026-10-01**, and **2026-10-02**; each section gives its environment. Documentation was read on +**2026-09-15** from the pages listed under Sources, and the SDK source on **2026-09-16**, except for section 8, +whose pages and SDK source were read on **2026-09-21**, section 9, whose pages were read on **2026-09-30**, and +section 10, whose pages were read on **2026-10-01** and **2026-10-02**. Microsoft revises these pages, so re-read a +page before relying on a limit or a permission. **Claims are labelled with their evidence.** @@ -53,6 +55,8 @@ relying on a limit or a permission. | [Microsoft Graph PowerShell SDK authentication source, branch `main`](https://github.com/microsoftgraph/msgraph-sdk-powershell/tree/main/src/Authentication) | none (branch, read 2026-09-21) | | [List chats](https://learn.microsoft.com/en-us/graph/api/chat-list?view=graph-rest-1.0) | 2026-04-13 | | [chat resource type](https://learn.microsoft.com/en-us/graph/api/resources/chat?view=graph-rest-1.0) | 2026-08-05 | +| [Integrate Microsoft Entra Agent ID with third-party identity providers](https://learn.microsoft.com/en-us/microsoft-agent-365/developer/third-party-identity-providers) | 2026-08-13 | +| [How the proxyAddresses attribute is populated in Microsoft Entra ID](https://learn.microsoft.com/en-us/troubleshoot/entra/entra-id/user-prov-sync/proxyaddresses-attribute-populate) | 2026-09-17 | ## 1. From documentation: permissions for each operation the module performs @@ -147,6 +151,12 @@ requests `Mail.Send` only. Chat attachments are uploaded with a simple `PUT` to that name is taken), shared with the chat recipients as read-only with sign-in required and no invitation email, and then referenced from the chat message. +**Measured** (2026-10-01, in the environment section 9 gives for that date): a chat attachment named +`plus+sign test.txt`, in a folder whose name also contains a `+`, was stored in OneDrive under exactly that name, +and Teams showed it under that name in the chat. The module escapes the name with `[uri]::EscapeDataString`, +which turns `+` into `%2B` in both PowerShell editions (measured locally the same day), so the `+` is kept rather +than read as a space. + ### What this does not establish - **Unverified:** the largest attachment, or total request size, that `sendMail` accepts inline. The 3 MB figure @@ -158,6 +168,8 @@ email, and then referenced from the chat message. comment in the module says it overwrites, and the module renames the file to avoid the question. - **Unverified:** that `Microsoft Teams Chat Files` is the folder Teams itself uses for chat attachments. The module assumes it; none of the pages above mention it. +- The `+` result was seen from the sender's side only; whether the recipients can open the shared file was not + checked. No other special character in a file name was tested. ## 6. From documentation: how SDK sign-in persists, and other clouds @@ -330,9 +342,9 @@ accounts the tester controls: the signed-in sender and two recipients. **Measured:** - `Get-MgChat -All -Filter "ChatType eq 'group'"` with `-ExpandProperty 'Members', 'LastMessagePreview'`, the - call the module makes, succeeded: Graph accepts both expansions in one request. Each of the signed-in account's - 6 group chats came back with its members' `email` values and a `LastMessagePreview`, and no two of them had the - same members. + call the module makes, succeeded: Graph accepts both expansions in one request. In a separate read-only run, + signed in as one of the recipient accounts instead of the sender, each of that account's 6 group chats came + back with its members' `email` values and a `LastMessagePreview`, and no two of them had the same members. - **A group chat with the same members as an existing one is a new chat.** `New-MgChat -BodyParameter`, with `chatType` `group` and the same three members as an existing group chat, returned a chat with a new ID and a `CreatedDateTime` of that moment. @@ -360,6 +372,31 @@ accounts the tester controls: the signed-in sender and two recipients. `user@odata.bind` value was present but named a user that does not exist (a quoted list of addresses passed as one address). The message says the field is missing when it is there but wrong. Both the `-Members` form and the `-BodyParameter` form gave it. +- **Timing** (read-only, signed in as the sender, 21 group chats, five alternating runs of each call): the + `Chat.Read` path's call, expanding `Members` and `LastMessagePreview`, took 580 to 780 ms, median 668 ms. The + `Chat.ReadBasic` path's call, expanding only `Members`, took 541 to 646 ms, median 573 ms. The `Chat.Read` call + was slower in all five pairs. + +**Measured on 2026-10-01** in the same environment, with `Microsoft.Graph.Files` 2.25.0 added, `Send-ScriptMessage` +from `develop` at `32282b7`, and the same three accounts: + +- **A recipient leaving a group chat in Teams changes the members the sender's listing returns.** One recipient + left both group chats holding all three accounts; afterwards the sender's `Get-MgChat` listing still returned + both, with only the two remaining members, so neither matched a send to all three. +- **The module's own `New-MgChat -Members` call creates a group chat with valid members.** With no group chat + holding exactly the sender and both recipients, `Send-ScriptMessage -ChatType Group` created one, of type + `group`, with exactly those three members, and posted its message into it. +- **A second send finds the chat the first one created.** The same send again posted into that chat, and the + sender still had only that one group chat with those three members. +- **A member's `email` can differ in letter case from the address the caller gave.** One recipient, given in + lower case, came back as a member `email` with capital letters. The match still succeeded: `Compare-Object` + ignores letter case unless given `-CaseSensitive`, in both PowerShell editions (measured locally the same day). +- **A recipient given by a UPN that differs from their primary email gets a new group chat instead of the + existing one.** One recipient's UPN was changed in Microsoft Entra ID to a name other than their primary email, + which stayed as it was. The sender's listing still showed that member's `email` as the primary address. A + `Group` send naming that recipient by the new UPN, with the other two members as before, found no match, + created a second group chat with the same three members as the existing one, and posted into it. Its `Error` + was empty, so the caller got no warning. Section 10 covers which forms of address find a user. **From documentation:** the chat resource type page defines `lastUpdatedDateTime` as "Date and time at which the chat was renamed or the list of members was last changed", and says `lastMessagePreview` is "Null if no messages @@ -381,20 +418,101 @@ values are exactly the sender plus the recipients, and creates a new group chat the same holds for every setting that only chooses which delegated permission is asked for. - A group chat with more than 25 members never matches, if the 25-member cap applies to `-All` paging too, so the module would create a new chat on every send to it. -- A recipient given by a UPN that differs from their primary email address never matches either, with the same - result: the module names each member as `users('
')`, which going by Graph's - `/users/{id | userPrincipalName}` form takes a user ID or UPN, but matches on the member's `email`, the primary - address. Matching on each member's `userId` would avoid it. A true alias, neither the UPN nor the primary - address, probably fails when the chat is created instead. +- The UPN mismatch measured above happens because the module names each member as `users('')`, which + going by Graph's `/users/{id | userPrincipalName}` form takes a user ID or UPN, but matches on the member's + `email`, the primary address. Each later send by UPN finds no match in the same way, so it creates yet another + chat. Matching on each member's `userId` would avoid it. ### What this does not establish -- **Unverified:** the module's own `New-MgChat -Members` call creating a group chat with valid members. A matching - chat already existed, so that path was not exercised. - **Unverified:** whether the Teams client ever creates a second group chat with the same members, and whether anything besides a rename or a member change moves `LastUpdatedDateTime` (only the documentation says so). -- **Unverified:** the 25-member cap, the UPN mismatch, and the alias failure in the inferences above. None was - tested. +- **Unverified:** the 25-member cap in the inferences above; it was not tested. +- The UPN mismatch was measured with one send. The account syncs from on-premises Active Directory, and its UPN + was changed in Microsoft Entra ID only. +- Only a three-member group chat was created. A `Group` send to a single recipient, which would match or create a + two-member group chat, was not tested. - **Unverified:** whether permissions a user consented to for themselves, rather than ones an administrator granted for the organization, are carried the same way. Only administrator grants were measured. +- How the timing gap grows with many more chats, and whether sorting on the server by + `lastMessagePreview/createdDateTime` would make the `Chat.Read` path faster. +- Nothing in this section was measured on Windows PowerShell 5.1 or with an SDK release other than 2.25.0. + +## 10. Measured: which forms of address find a user + +**Environment:** measured on 2026-10-01 and 2026-10-02 in the environment section 9 gives for 2026-10-01, with +the same code and the same three accounts. Chat sends used a delegated sign-in, and the mail send the +`Mail.Send` application permission. The accounts sync from on-premises Active Directory. On 2026-10-01 one +recipient's UPN was changed in Microsoft Entra ID only, to a name other than their primary email, which stayed +as it was, and it stayed changed through every test below. + +**Measured:** + +- **A chat member given by UPN resolves.** A `Group` send naming that recipient by the new UPN created a group + chat with them as a member (section 9). On 2026-10-02 a `OneOnOne` send to the same UPN posted into the + existing one-on-one chat between the two accounts, created in 2024, with `Error` empty. +- **A chat member given by primary email resolves while it is not the UPN.** On 2026-10-01, and again on + 2026-10-02, a `OneOnOne` send to that recipient's primary email posted into the same one-on-one chat, with + `Error` empty. +- **A secondary email address that was never a UPN does not resolve.** On 2026-10-01 a `OneOnOne` send with + `From` set to one of the sender's own secondary SMTP addresses, which had never been their UPN, failed in + `New-MgChat` with 404 `Failed to find users with user principal name ''`. Nothing was posted. The + result's `Error` held only the module's warning `Cannot create a chat with the recipient '