[BUG] Get-PnPEntraIDGroupMember -Transitive: UserType intermittently null because Graph ignores $select=* on transitiveMembers

Đang mở Phù hợp với người mới
#5,506 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
72/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
csharp, powershell
Lĩnh vực
backend-api-design

Hướng nghiên cứu

Đọc src/Commands/EntraID/GetEntraIDGroupMember.cs và src/Commands/Utilities/Microsoft365GroupsUtility.cs, đặc biệt là lời gọi GetTransitiveMembers và truy vấn $select=* của lời gọi đó. Kiểm tra cách yêu cầu Graph hiện có chọn các thuộc tính và cmdlet trả về những thuộc tính nào của thành viên. Kết quả cần đạt là các kết quả bắc cầu luôn bao gồm UserType, UsageLocation và ProxyAddresses; issue không nêu tên tệp kiểm thử.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

bug
Description

Since November 11, 2026 (around 17:00 UTC+1), Get-PnPEntraIDGroupMember -Transitive intermittently returns user objects with UserType = $null. About 15–30% of the calls in our tests are affected.

UsageLocation and ProxyAddresses are $null on the same calls. Only the properties of the Graph default set are populated, including UserPrincipalName.

Root cause (from the source and direct Graph calls)

With -Transitive, the cmdlet calls Microsoft365GroupsUtility.GetTransitiveMembers, which sends:

v1.0/groups/{groupId}/transitiveMembers?$select=*
  • v3.5.0 (latest): src/Commands/EntraID/GetEntraIDGroupMember.cs → src/Commands/Utilities/Microsoft365GroupsUtility.cs (lines 435 and 442)

Microsoft Graph intermittently ignores $select=* on this endpoint and returns only the default property set. That set has 12 properties (id, businessPhones, displayName, givenName, jobTitle, mail, mobilePhone, officeLocation, preferredLanguage, surname, userPrincipalName, plus @odata.type). It does not include userType. An explicit property list is always honoured.

Direct calls with Invoke-PnPGraphMethod, same app, same group (39 users), 40 calls each:

  • v1.0/groups/{id}/transitiveMembers?$select=*
    → 6/40 responses with the 12 default properties only (userType missing); 34/40 full (67 properties)
  • v1.0/groups/{id}/transitiveMembers?$select=id,userPrincipalName,userType,usageLocation
    → userType present in 40/40 responses

The cmdlet reflects exactly what Graph returns. Over 25 calls with PnP.PowerShell 3.5.0:

  • 18/25: UserType set on all 39 users
  • 7/25: UserType $null on all 39 users, UsageLocation $null as well

The underlying behaviour is on the Graph side. Using an explicit $select list in GetGroupMembers instead of $select=* would make the cmdlet reliable.

Impact

We sync SharePoint site membership from Entra groups. Our script kept only members with UserType -in 'Member','Guest'.

When UserType came back $null, the source groups looked empty:

  1. the script removed every member from the target Microsoft 365 groups;
  2. the next run added them back;
  3. this repeated every 20 to 30 minutes, about 6,000 adds and 6,700 removals in 15 hours;
  4. users received "Welcome to the … group" emails in a loop.
Steps to reproduce
Connect-PnPOnline -ClientId <appId> -Thumbprint <thumbprint> -Tenant <tenant>.onmicrosoft.com -Url <tenant>.sharepoint.com
$id = '<group id>'
1..25 | ForEach-Object {
    $m = @(Get-PnPEntraIDGroupMember -Identity $id -Transitive)
    # Note: [UserType]::Member = 0, so do not test with -not $_.UserType
    '{0:HH:mm:ss} count={1} userTypeNull={2} usageLocationNull={3}' -f (Get-Date), $m.Count,
        @($m | Where-Object { $null -eq $_.UserType }).Count,
        @($m | Where-Object { -not $_.UsageLocation }).Count
    Start-Sleep -Milliseconds 500
}
Expected

UserType is populated on every call, as it was before 2026-11-11.

Environment
  • PnP.PowerShell 3.5.0 (latest release); also reproduced on 3.1.0
  • PowerShell 7.6.4, Windows Server 2019 Standard
  • App-only authentication with a certificate
  • Source groups: security groups synced from on-premises AD with Entra Connect
Workaround

We now filter on UserPrincipalName instead of UserType:

$users = @($members | Where-Object { -not [string]::IsNullOrWhiteSpace($_.UserPrincipalName) })

This is equivalent in our case because the UserType filter was not meant to tell members from guests: -in 'Member','Guest' keeps both values. Its only real effect was to keep users and drop any other directory objects a transitive query could return (nested groups, devices, contacts, service principals).

UserPrincipalName makes the same split:

  • member users have a UPN ([email protected]);
  • guest users have a UPN too (user_fabrikam.com#EXT#@contoso.onmicrosoft.com);
  • groups, devices and contacts have no UPN.

It is also reliable, because userPrincipalName is part of the default property set that Graph falls back to.

This workaround does not help anyone who needs to tell members from guests. They still need a reliable UserType, for example by calling Graph directly with an explicit $select=userType.

We also added a safeguard: if a source group returns members but none of them has a UPN, the sync stops for that site instead of emptying the target group.

Ngôn ngữ chính
C#
Star
912
Fork
407
Merge trung bình
23 giờ 19 phút
Pull request đã merge (30 ngày)
9

Chuẩn bị môi trường

Mở trong Codespaces

Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của pnp/powershell

Tất cả issue của pnp/powershell

Issue tương tự

Thêm issue về C#

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.