Informar reuniones en línea de Teams con PowerShell y Graph
Mejor que auditar eventos para extraer todos los detalles de las reuniones en línea de Teams
Es fantástico que Microsoft finalmente ponga el conjunto de eventos de auditoría adicionales a disposición de los inquilinos con licencias Purview Audit (Estándar). Algunos podrían estar entusiasmados con la posibilidad de poder analizar datos de reuniones en línea de Teams de los eventos MeetingDetail y MeetingParticipantDetail, pero como señalo en otra parte, la información disponible en esos eventos no es tan completo como podría imaginarse.
Aunque los eventos de auditoría son útiles y pueden ser la solución adecuada en muchos casos, si desea saber todo sobre una reunión en línea de Teams, las API de Microsoft Graph son la única respuesta. Este artículo explica cómo usar las API Graph para buscar eventos en línea de Teams en los calendarios de los usuarios y extraer la información de asistencia y otros detalles de las reuniones. Hay disponible un script de PowerShell completamente funcional que puede adaptar para satisfacer sus propios requisitos.
El enfoque básico es conectarse a Microsoft Graph en modo de solo aplicación (usando una aplicación Entra ID para autenticarse) y usar los permisos de Graph asignados a la aplicación para leer datos de los calendarios de los usuarios y la tienda de Teams. El último paso es generar un informe HTML a partir de los datos.
Cree una aplicación Entra ID para acceder a reuniones en línea
El primer paso es crear una aplicación Entra ID para tener los permisos necesarios para recuperar datos de reuniones en línea de Teams, datos de calendario y otra información. La aplicación necesita un certificado X.509 (autogenerado o comprado) para la autenticación. Después de crear la aplicación, asigne los siguientes permisos de aplicación:
- Calendars.Read: lee los datos del calendario para encontrar reuniones en línea para procesar.
- Group.Read.All: lea la membresía del grupo para encontrar las cuentas a procesar.
- OnlineMeetings.Read.All: lee los datos de las reuniones en línea de Teams.
- OnlineMeetingArtifact.Read.All: lea informes de asistencia para reuniones en línea de Teams.
- CrossTenantInformation.ReadBasic.Todos: lee la información en los informes de asistentes para resolver el nombre del inquilino para los participantes externos (federados).
- Organization.Read.All: lee información sobre el inquilino (como su nombre para mostrar).
La Figura 1 muestra el conjunto de permisos de aplicación asignados y consentidos para la aplicación utilizada por el script.
Tenga en cuenta el identificador de la aplicación (cliente), el identificador del inquilino (directorio) y la huella digital del certificado de las propiedades de la aplicación. Almacene los valores en variables de PowerShell para usarlos en el script. Estos elementos se utilizan para autenticarse al conectarse a Graph con el cmdlet Connect-MgGraph.
Crear una política de acceso a aplicaciones
Con los permisos de la aplicación, la aplicación puede acceder a datos de todo el inquilino. Bueno, sí, pero sólo para grupos, calendarios e información entre inquilinos. Los permisos de aplicación utilizados para acceder a las reuniones en línea de Teams tienen un nivel adicional de protección llamado política de acceso a la aplicación.
Una política de acceso a la aplicación vincula una o más aplicaciones de Entra ID con cuentas para permitir que las aplicaciones procesen datos de Teams en línea que pertenecen a esas cuentas. En algunos aspectos, es como el mecanismo RBAC para aplicaciones utilizado por Exchange Online para restringir el acceso a los buzones de correo.
El centro de administración de Teams no admite la gestión de políticas de acceso a aplicaciones. Estas acciones deben realizarse con PowerShell. Primero, creamos una política de acceso a la aplicación ejecutando el cmdlet New-CsApplicationAccessPolicy:
New-CsApplicationAccessPolicy -Identity 'Read Teams Meeting Data' -AppIds "78b6e21f-127d-470d-a61b-295d5c2d058c" -Description "Permission to read Teams Meetings for users"
Identity : Tag:Read Teams Meetings
AppIds : {78b6e21f-127d-470d-a61b-295d5c2d058c}
Description : Permission to read Teams Meetings for users
Con la política de acceso a la aplicación creada, podemos otorgarla a las cuentas cuyos datos de reuniones en línea debe procesar el script. Es posible otorgar una política de acceso a la aplicación a todas las cuentas a las que no se les ha asignado una política específica, pero en este caso, ejecutamos el cmdlet Grant-CsApplicationAccessPolicy para cuentas específicas. Ejecute el cmdlet para cada cuenta y pase el identificador de la cuenta como cesionario. O el nombre principal del usuario o el GUID funcionan:
Grant-CsApplicationAccessPolicy -PolicyName 'Read Teams Meeting Data' -Identity 21a3ce8f-6d55-4e57-9210-d85a2f1618ecPuede asignar solo una política de acceso a la aplicación a la vez a un usuario en particular. La asignación de una nueva política de acceso a aplicaciones a un usuario anula cualquier política de acceso a aplicaciones existente. Además, solo es posible otorgar una política de acceso a la aplicación a una cuenta de miembro con una licencia de Teams válida. Pueden pasar hasta 30 minutos antes de que una concesión de acceso a la aplicación permita que una aplicación acceda a los datos de la reunión en línea.
Luego de realizar las asignaciones, verifica las cuentas con las que la aplicación puede procesar:
Get-CsOnlineUser -Filter {ApplicationAccessPolicy -eq "Read Teams Meeting Data"} | Select-Object DisplayName,UserPrincipalName,ApplicationAccessPolicy
DisplayName UserPrincipalName ApplicationAccessPolicy
----------- ----------------- -----------------------
Alex Wilber AlexW@o365maestro.onmicrosoft.com Read Teams Meeting Data
"Popeye" Doyle Popeye.Doyle@o365maestro.onmicrosoft.com Read Teams Meeting Data
Alain Charnier Alain.Charnier@o365maestro.onmicrosoft.com Read Teams Meeting Data
Conéctese a Microsoft Graph
Después de esperar a que las asignaciones de políticas sean efectivas, conéctese a Microsoft Graph con el SDK de Microsoft Graph PowerShell. Queremos utilizar los permisos asignados a la aplicación que tiene acceso a los datos en línea para las cuentas especificadas, por lo que Connect-MgGraph incluye el identificador de la aplicación, el identificador del inquilino y la huella digital del certificado en sus parámetros:
$AppId = "78b6e21f-127d-470d-a61b-295d5c2d058c"
$TenantId = "22e90715-3da6-4a78-9ec6-b3282389492b"
$CertThumbprint = "F79286DB88C21491110109A0222348FACF694CBD"
Connect-MgGraph -AppId $AppId -TenantId $TenantId -CertificateThumbprint $CertThumbprint
Para comprobar que todos los permisos necesarios están disponibles, ejecute Get-MgContext. El script solo funcionará si los cinco permisos que se enumeran a continuación están disponibles para la sesión:
(Get-MgContext).scopes
OnlineMeetings.Read.All
OnlineMeetingArtifact.Read.All
Calendars.Read
Group.Read.All
CrossTenantInformation.ReadBasic.All
Organization.Read.All
Pasos para procesar reuniones en línea de Teams
El script utiliza los siguientes pasos:
- Busque el conjunto de cuentas de usuario para las que extraer datos de reuniones en línea de Teams. Para facilitar la administración del conjunto de cuentas, el script utiliza una lista de distribución para contener las cuentas y lee la membresía con el cmdlet Get-MgMemberGroup .
- Para cada cuenta, lea el conjunto de eventos de la carpeta del calendario en el buzón del usuario y extraiga el conjunto de reuniones de Teams en línea.
- Para cada reunión, extraiga los detalles, incluidos los informes de asistencia.
- Generar un informe a partir de los datos.
Todo parece sencillo, pero como siempre, hay algunos detalles que se interponen en el camino.
Algunos problemas que se deben abordar al obtener datos de reuniones en línea de Teams
En primer lugar, el acceso a los datos de las reuniones en línea de Teams parece detenerse después de aproximadamente 60 días. La información del calendario siempre está disponible, pero no los detalles sobre el aspecto online. Parece que Teams saca los datos de su reunión del caché en línea después de 60 días y cualquier intento posterior de devolver detalles sobre una reunión falla. Si intenta abrir una reunión antigua en un cliente de Teams, podrá ver los datos. Supongo que se utiliza alguna otra API para recuperar los datos antiguos y cargarlos en el caché.
Este es un ejemplo de dónde los eventos de auditoría son mejores. Si tiene licencias Purview Audit (Estándar), los datos están disponibles durante 180 días. Con Purview Audit (Premium), los datos están disponibles durante 365 días.
Decodificación y codificación de identificadores de reuniones
En segundo lugar, probablemente conozca la URL de la reunión publicada para cada reunión de Teams. Cuando se utiliza la API Get onlineMeeting para recuperar detalles de la reunión, la API requiere el identificador de un objeto de reunión en línea. La documentación no es muy útil en términos de definir el formato del identificador de la reunión, pero algunas búsquedas revelaron un método que sigue los siguientes pasos:
- Obtenga la URL para unirse a la reunión. El valor será algo como: https://teams.microsoft.com/l/meetup-join/19%3ameeting_YzU5NTYwM2QtMmU3YS00YmNlLWEwZWMtNzA0NTk4OTZlNjJi%40thread.v2/0?context=%7b%22Tid%22%3a%22a662313f-14 FC -43a2-9a7a-d2e27f4f3478%22%2c%22Oid%22%3a%225b52fba5-349e-4622-88cd-d790883fe4c4%22%7d (según MC772556, Microsoft planea adoptar un formato de URL de reunión más corto desde agosto de 2024).
- Decodifica la URL.
- Busque el identificador de la reunión en la URL decodificada para unirse a la reunión (un valor como 19:meeting_ZmY4YTJhNmUtY2Y3OS00ZGZlLWI1ODEtYjA2ZTZmZjA0YzQ0@thread.v2).
- Cree un valor de búsqueda formateado de una manera específica. El valor contiene el identificador de usuario para el organizador y el identificador de la reunión y tiene este aspecto: 1*880e1e61-af63-43c9-a48e-d6b63684c21c*0**19:meeting_ZmY4YTJhNmUtY2Y3OS00ZGZlLWI1ODEtYjA2ZTZmZjA0YzQ0@thread.v2.
- Cree un valor codificado en BASE64 del identificador de búsqueda de reuniones.
Supongo que Microsoft ofusca los identificadores de reuniones de Teams de esta manera para limitar la posibilidad de que alguien haga un uso indebido de un identificador para acceder a reuniones que no debería. En cualquier caso, aquí está el código de PowerShell que utilicé:
$MeetingURL = $Item.onlinemeeting.joinUrl.trim()
$DecodedURL = [System.Web.HttpUtility]::UrlDecode($MeetingURL)
$MeetingIdStart = $DecodedURL.IndexOf("19:")
$MeetingIdEnd = $DecodedURL.IndexOf("thread")
$MeetingId = $DecodedURL.Substring($MeetingIdStart, $MeetingIdEnd - $MeetingIdStart +9)
$MeetingIdLookup = ("1*{0}*0**{1}" -f $Organizer.id, $MeetingId)
$Base64MeetingId = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($MeetingIdLookup))
Luego, el script puede construir un URI para usarlo con una solicitud Graph. La URI se parece a:
https://graph.microsoft.com/v1.0/users/880e1e61-af63-43c9-a48e-d6b63684c21c/onlineMeetings/MSo4ODBlMWU2MS1hZjYzLTQzYzktYTQ4ZS1kNmI2MzY4NGMyMWMqMCoqMTk6bWVldGluZ19 abVk0WVRKaE5tVXRZMlkzT1MwMFpHWmxMV0kxT0RFdFlqQTJaVFptWmpBMFl6UTBAdGhyZWFkLnYy
El valor de retorno son los detalles que Teams tiene sobre la reunión en línea.
Después de eso, lo único que queda por resolver es el hecho de que una reunión puede comenzar y detenerse varias veces. Cada instancia genera un informe de asistencia y otros artefactos, como una transcripción.
Nos interesa saber quién asiste a cualquier instancia de una reunión, por lo que el script busca todos los informes de asistencia y extrae los datos de asistencia para cada informe.
El informe
No importa lo bueno que sea un script de PowerShell, si no produce resultados útiles, el código es inútil. En este caso, el resultado es un informe HTML que enumera las reuniones en línea por usuario con detalles de la reunión y su asistencia (Figura 2).
Tenga en cuenta que cuando las cuentas de invitados asisten a una reunión, normalmente cambian al inquilino anfitrión antes de unirse (una disciplina impuesta por algunas organizaciones). Esto hace que parezca que la cuenta es de ese inquilino (que lo es), por lo que no ve el nombre del inquilino de la casa, excepto para los asistentes federados (aquellos que inician sesión para asistir a una reunión en otro inquilino usando su propia cuenta).
El script está disponible en GitHub. Espero que el código de PowerShell sea comprensible. Si no es así, asegúrese de solucionarlo por mí. Puedo utilizar toda la ayuda que pueda conseguir.

