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

Abierto Apto para principiantes
#5,506 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Los mantenedores suelen responder en 1 día

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
72/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
csharp, powershell

Línea de trabajo

Lee src/Commands/EntraID/GetEntraIDGroupMember.cs y src/Commands/Utilities/Microsoft365GroupsUtility.cs, especialmente la llamada a GetTransitiveMembers y su consulta $select=*. Comprueba cómo la solicitud de Graph existente selecciona las propiedades y qué propiedades de los miembros devuelve el cmdlet. El objetivo se cumple cuando los resultados transitivos incluyen sistemáticamente UserType, UsageLocation y ProxyAddresses; el issue no especifica ningún archivo de pruebas.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
C#
Estrellas
912
Forks
407
Merge medio
23 h 19 min
PR fusionados (30 d)
9

Preparar el entorno

Abrir en Codespaces

Inicia el contenedor de desarrollo del proyecto en tu navegador, con tu propia cuenta de GitHub.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de pnp/powershell

Todos los issues de pnp/powershell

Issues similares

Más issues de C#

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.