Búsqueda de sitios web

Gráfico práctico: trabajar con Teams Mensajería


Elegir entre módulos

Una nueva versión del módulo PowerShell de Microsoft Teams suele generar cientos de miles de descargas desde la Galería de PowerShell. Si bien la cantidad de descargas no es una indicación del uso, es razonable suponer que la mayoría de los que descargan el módulo lo usan para administrar Teams. El SDK de Microsoft Graph PowerShell también incluye cmdlets para trabajar con Teams, como Get-MgTeam, Get-MgTeamChannel, etc., muchos de los cuales se encuentran cmdlets duplicados en Microsoft Módulo de equipos. Dada la duplicación, ¿qué camino deberían tomar los administradores para automatizar las operaciones de Teams?

La respuesta no es sencilla porque depende de lo que intentes hacer. Aquí hay algunos puntos para recordar:

  • Ambos módulos tienen enlaces a Microsoft Graph. Muchos de los cmdlets del módulo Microsoft Teams se basan en las API Graph y todos los cmdlets del SDK de Microsoft Graph PowerShell se derivan de las API Graph.
  • El módulo Microsoft Teams incluye otros cmdlets que no se basan en las API Graph. La mayoría son cmdlets de administración de políticas que provienen originalmente del conector de Skype Empresarial.
  • El SDK de Microsoft Graph PowerShell incluye cmdlets para interactuar con otras cargas de trabajo de Microsoft 365 y Entra ID.
  • El módulo Microsoft Teams está diseñado para automatizar las operaciones de gestión. Cuando los usa una cuenta que tiene la función de administrador global o administrador de Teams, los cmdlets pueden administrar todos los equipos de una organización.
  • El SDK de Microsoft Graph PowerShell incluye cmdlets que pueden interactuar con el contenido del usuario, como publicar nuevos chats. Se necesitan diferentes permisos para interactuar con diferentes datos de Teams. Los desarrolladores también deben recordar la diferencia entre permisos delegados y permisos de aplicaciones cuando se trata de acceder a datos.

En la mayoría de los casos, es más fácil usar el módulo Microsoft Teams para la automatización general e introducir el SDK de Microsoft Graph PowerShell cuando sea necesario interactuar con los datos del usuario, como publicar o eliminar chats, que es lo que queremos hacer aquí.

El resto de este artículo cubre los conceptos básicos de la mensajería de Teams y explica cómo publicar mensajes en chats individuales y grupales y conversaciones de canal utilizando el SDK de Microsoft Graph PowerShell. El proceso de eliminar mensajes de los canales se trata en un artículo diferente.

Una nota sobre los permisos

Como probablemente sepa, el modelo de permisos utilizado para las solicitudes de Graph API es una base de privilegios mínimos. En la mayoría de los casos, los permisos de la aplicación están disponibles para permitir que las aplicaciones que usan solicitudes Graph se ejecuten como procesos en segundo plano, como un trabajo programado de Azure Automation.

No hay permisos de aplicación disponibles para solicitudes de Graph, como publicar mensajes en chats o conversaciones de canal, por lo que se deben utilizar permisos delegados. La aplicación necesita el permiso ChannelMessage.Send para publicar mensajes en canales y el permiso Chat.Create para publicar en un chat. Se requieren permisos adicionales (como Chat.ReadWrite) para recuperar mensajes.

Debido a la falta de permisos de la aplicación, la cuenta iniciada debe ser miembro de un chat o equipo para publicar mensajes y propietario del equipo para eliminar mensajes del canal. Las identidades administradas de Azure Automation no se pueden usar porque estas identidades no pueden ser miembros de un equipo o chat.

La solución habitual es iniciar sesión en Teams utilizando una cuenta de utilidad que sea miembro del equipo y publicar en canales de esa manera. En el pasado, hice esto usando el módulo PnP del cmdlet Submit-PnPTeamsChannelMessage usando credenciales almacenadas en Azure Key Vault. La misma técnica funciona con los cmdlets que se tratan aquí.

Cargas útiles de chat

Teams admite chats individuales y grupales. El primer ejemplo crea un nuevo chat individual entre dos cuentas de inquilinos. La documentación de Microsoft incluye varios buenos ejemplos de cómo publicar mensajes en chats. Sin embargo, creo que el método utilizado para construir la carga útil JSON para publicar en Teams es demasiado complicado y no se presta a la manipulación programática.

Por lo tanto, adopto un enfoque diferente para definir y extraer las matrices y tablas hash que forman la carga útil. Es el mismo enfoque que se utiliza para crear parámetros para publicar tareas del Planificador en un plan. Utilice el enfoque adoptado en los ejemplos de documentación si lo desea. Funcionan y son buenos ejemplos, pero creo que mi método es mejor para guiones de producción.

Crear y publicar en un chat uno a uno

Primero, definimos una matriz que contiene los identificadores de cuenta de los participantes del chat y la tabla hash que contiene la carga útil (también conocida como el cuerpo de la solicitud) utilizada para crear el chat. El código también agrega un parámetro para identificar el chat como uno a uno. Debes utilizar el formato exacto (onOnOne) para identificar el tipo de chat.

[array]$MemberstoAdd = "eff4cd58-1bb8-4899-94de-795f656b4a18", "cad05ccf-a359-4ac7-89e0-1e33bf37579e"
$OneOnOneChatBody = @{}
$OneOnOneChatBody.Add("chattype", "oneOnOne")

Las partes restantes de la carga útil definen a los participantes del chat. Estos datos se pasan en una matriz compuesta por dos tablas hash. Cada tabla hash contiene información sobre un participante del chat, uno de los cuales debe ser el usuario que inició sesión. Como puede ver, el código permite agregar una cuenta de invitado como participante del chat.

$Members = @()
ForEach ($Member in $MemberstoAdd) {
    $User = Get-MgUser -UserId $Member -Property id, displayName, userType, userprincipalName
    $MemberId = ("https://graph.microsoft.com/v1.0/users('{0}')" -f $Member)
    $MemberDetails = @{}
    [array]$MemberRole = "owner"
    If ($User.userType -eq "Guest") {
        [array]$MemberRole = "guest"
    }
    $MemberDetails.Add("roles", $MemberRole.trim())
    $MemberDetails.Add("@odata.type", "#microsoft.graph.aadUserConversationMember")
    $MemberDetails.Add("user@odata.bind", $MemberId.trim())
    $Members += $MemberDetails
}
$OneOnOneChatBody.Add("members", $Members)

La carga útil completa se ve así:

$OneOnOneChatBody

Name                           Value
----                           -----
chattype                       oneOnOne
members                        {System.Collections.Hashtable, System.Collections.Hashtable}

Ahora podemos ejecutar el cmdlet New-MgChat para crear un chat. Si ya existe un chat para los dos participantes, Teams devuelve el identificador de chat para ese chat. De lo contrario, Teams crea un nuevo chat y devuelve ese identificador, que tiene un valor como 19:949d2f6c2b1f4f50b42714ddb2be4a36@thread.v2.

$NewChat = New-MgChat -BodyParameter $OneOnOneChatBody
If ($NewChat) {
    Write-Host ("New chat {0} created" -f $NewChat.id)
} Else {
    Write-Host "Failed to create chat"
}

Conocer el identificador del chat nos permite ejecutar el cmdlet New-MgChatMessage para publicar un mensaje en el chat. Este código crea contenido HTML y lo publica en el chat.

$Content = "<b><i>Using the Microsoft AuditLog Query Graph API (Preview)</b></i><p>"
$Content = $Content + "The unified audit log is the source of a lot of information about a Microsoft 365 tenant. The Search-UnifiedAuditLog cmdlet is available to search the audit log and now we have the AuditLog Graph API. This article explains how to use the new API to query and retrieve audit records from the log."
$Content = $Content + "<p>For more information, see <a href='https://practical365.com/audit-log-query-api/'>https://practical365.com/audit-log-query-api/</a>"

$ChatMessageBody = @{}
$ChatMessageBody.Add("contentType", "html")
$ChatMessageBody.Add("content", $Content) 
$ChatMessage = New-MgChatMessage -ChatId $NewChat.Id -Body $ChatMessageBody

La figura 1 muestra el mensaje publicado en el chat.

Crear y publicar en un chat grupal

Un chat grupal tiene entre dos y 250 participantes. También puede tener un tema (título). Para demostrar cómo agregar una gran cantidad de participantes a un nuevo chat grupal, este código encuentra un equipo que usa un filtro AF para un nombre para mostrar específico y extrae su lista de miembros en una serie de identificadores de cuentas de usuario. También crea la tabla hash para que la carga útil cree el nuevo chat y completa el tipo y tema del chat:

$Members = @()
$Team = Get-MgTeam -Filter "displayName eq 'Information Quality and Accuracy'"
If ($Team) {
   [array]$TeamMembers = (Get-MgGroupMember -GroupId $Team.Id).Id 
}
# Create a new group chat
$GroupChatBody = @{}
$GroupChatBody.Add("chattype", "group")
$GroupChatBody.Add("topic", "Major Updates - Urgent News")

El siguiente paso crea un conjunto de tablas hash para definir cada miembro y agregarlo al chat grupal. Al igual que en un chat individual, uno de los participantes de un chat grupal debe ser el usuario que haya iniciado sesión. Debido a que es una función de vista previa, el código excluye las cuentas de los miembros del equipo sincronizadas desde una organización multiinquilino. Finalmente, el cmdlet New-MgChat crea el nuevo chat.

ForEach ($Member in $TeamMembers) {
   $User = Get-MgUser -UserId $Member -Property id, displayName, userType, userprincipalName
   # Exclude MTO accounts
   If (($User.userprincipalName -notlike "*#EXT#*" -and $User.userType -eq "Member") -or $User.userType -eq "Guest") {
        Write-Host ("Processing member {0}" -f $User.DisplayName)
        $MemberId = ("https://graph.microsoft.com/v1.0/users('{0}')" -f $Member)
        $MemberDetails = @{}
        [array]$MemberRole = "owner"
        If ($User.userType -eq "Guest") {
            [array]$MemberRole = "guest"
        }
        $MemberDetails.Add("roles", $MemberRole.trim())
        $MemberDetails.Add("@odata.type", "#microsoft.graph.aadUserConversationMember")
        $MemberDetails.Add("user@odata.bind", $MemberId.trim())
        $Members += $MemberDetails
  }
}
# Add the membership information to the parameter body
$GroupChatBody.Add("members", $Members)
$NewGroupChat = New-MgChat -BodyParameter $GroupChatBody

La Figura 2 muestra la membresía del chat grupal creado por el código anterior.

El mismo comando New-MgChatMessage utilizado para publicar un mensaje en un chat individual publicará un mensaje en el chat grupal.

Múltiples chats grupales

Si bien Teams reutiliza un chat individual cuando existe uno, es posible crear varios chats grupales con temas idénticos. Al igual que la foto de chat personalizable, los clientes de Teams utilizan el tema con fines de visualización para ayudar a los usuarios a encontrar chats en la lista de chats. El identificador de chat es la forma de hacer referencia a chats específicos. Esto significa que el código debe tener cuidado con el chat al que se dirige cuando publica mensajes. Por ejemplo, si ejecuta el cmdlet Get-MgChat para recuperar detalles de chats grupales, es posible que vea algo como esto:

$GroupChats = Get-MgChat -filter "ChatType eq 'group'"
$GroupChats | Format-Table Topic, Id

Topic                             Id
-----                             --
Major Updates - Urgent News       19:1741422a23464620a6e71f363db2d51a@thread.v2
Major Updates - Urgent News       19:949d2f6c2b1f4f50b52714ddb2be4a36@thread.v2
Major Updates - Urgent News       19:5f6deae375f84b3396a9648722ba62b8@thread.v2
Warnings                          19:b2db6ce5bfb348709dccd9b8f959dfae@thread.v2

Para distinguir entre los chats con el mismo tema, debes verificar otros detalles como los miembros del chat (Get-MgChatMembers) o la marca de tiempo de la última actualización.

Publicar notas base y respuestas en un canal

Teams organiza los mensajes que componen las conversaciones del canal (hilos) en notas base y respuestas. Este código encuentra el identificador del canal general del equipo que usamos anteriormente y usa el cmdlet New-MgTeamChannelMessage para publicar un mensaje como una nueva nota base (conversación).

Como deberían tener todas las conversaciones del canal, la nota base tiene un asunto para indicar a los usuarios qué tema cubre la conversación. El código también marca el mensaje (un paso opcional). Si la publicación del mensaje se realiza correctamente, el código recupera los detalles de la nota con el cmdlet Get-MgTeamChannelMessage e informa los detalles de quién publicó el mensaje y la fecha de publicación.

[array]$TeamChannel = Get-MgTeamChannel -TeamId $Team.Id -Filter "displayName eq 'General'"
$ChatMessageBody = @{}
$ChatMessageBody.Add("contentType", "html")
$ChatMessageBody.Add("content", $Content)
$ChannelMessage = New-MgTeamChannelMessage -TeamId $Team.Id -ChannelId $TeamChannel.Id -Body $ChatMessageBody -Subject "Really Important News" -Importance "urgent"
$MessageContents = Get-MgTeamChannelMessage -TeamId $Team.Id -ChannelId $TeamChannel.Id -ChatMessageId $ChannelMessage.Id
If ($MessageContents) {
    Write-Host ("Channel message posted by {0} at {1}" -f $MessageContents.from.user.displayName, $MessageContents.createdDateTime)
}

Para agregar una respuesta a la conversación, ejecute el cmdlet New-MgTeamChannelMessageReply y pase el identificador de la nota base.

$ReplyMessageBody = @{}
$ReplyMessageBody.Add("contentType", "html")
$ReplyMessageBody.Add("content", "This is a reply...")
$ReplyMessage = New-MgTeamChannelMessageReply -TeamId $Team.Id -ChannelId $TeamChannel.Id -ChatMessageId $ChannelMessage.Id -Body $ReplyMessageBody
If ($ReplyMessage) {
    Write-Host ("Reply posted by {0} at {1}" -f $ReplyMessage.from.user.displayName, $ReplyMessage.createdDateTime) 
}

La Figura 3 muestra el resultado de publicar la nota base y una respuesta al canal General.

Más opciones de mensajería de Teams para cubrir

Con suerte, estos ejemplos brindan información sobre cómo funcionan los cmdlets de mensajería de Teams en el SDK de Microsoft Graph PowerShell. Existen otras posibilidades, como incluir archivos adjuntos o menciones en los mensajes. La documentación de Microsoft le ayudará a explorar los parámetros necesarios o tal vez los analice en un artículo futuro.

Artículos relacionados