Skip to content

Commit 6731df1

Browse files
committed
feat(docs): create guide for bulk adding members to Teams shared channels using PowerShell and Microsoft Graph
1 parent 0ba3f0a commit 6731df1

File tree

1 file changed

+309
-0
lines changed

1 file changed

+309
-0
lines changed
Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
---
2+
draft: false
3+
date: 2025-09-27
4+
authors:
5+
- rfernandezdo
6+
categories:
7+
- Productividad / Microsoft 365
8+
tags:
9+
- Teams
10+
- Shared Channels
11+
- PowerShell
12+
- Microsoft Graph
13+
- CSV
14+
- Bulk Operations
15+
---
16+
17+
# Añadir miembros a canales compartidos de Teams en modo bulk
18+
19+
## Resumen
20+
21+
Añadir usuarios (internos y externos) uno a uno en canales compartidos de Teams es tedioso. Este post muestra cómo automatizar el proceso usando PowerShell, Microsoft Graph y un archivo CSV como origen de datos para añadir múltiples usuarios de forma eficiente.
22+
23+
<!-- more -->
24+
25+
## ¿Qué son los canales compartidos en Teams?
26+
27+
Los **canales compartidos** permiten colaborar con personas de tu organización y externas sin necesidad de cambiar de tenant. Puedes añadir:
28+
29+
- **Usuarios internos** de tu propia organización
30+
- **Usuarios externos** que mantienen su identidad de origen mediante **B2B Direct Connect**
31+
32+
A diferencia de los guest users tradicionales, los participantes externos en canales compartidos conservan su tenant original.
33+
34+
**Características clave:**
35+
36+
- Soportan usuarios internos y externos en el mismo canal
37+
- Usuarios externos no necesitan cuentas guest (B2B Collaboration)
38+
- Los usuarios externos conservan su tenant original
39+
- Configuración de B2B Direct Connect solo necesaria para usuarios externos
40+
- Usan UPN (User Principal Name) para identificación
41+
42+
## Limitaciones importantes
43+
44+
!!! warning "Restricciones críticas"
45+
- **Guest users NO pueden añadirse** a canales compartidos (incluso si su UserType es "Member")
46+
- Debes usar el **UPN del usuario**, no su email (si difieren en Microsoft Entra ID)
47+
- Requiere configuración previa de **B2B Direct Connect** entre organizaciones
48+
- Las políticas de **Information Barriers** pueden bloquear la adición
49+
50+
## Arquitectura de la solución
51+
52+
```mermaid
53+
flowchart LR
54+
A[CSV File] -->|Import-Csv| B[PowerShell Script]
55+
B -->|Connect-MgGraph| C[Microsoft Graph API]
56+
C -->|Add-MgTeamChannelMember| D[Shared Channel]
57+
D --> E[External Users]
58+
59+
style A fill:#e1f5ff
60+
style D fill:#c8e6c9
61+
style E fill:#fff9c4
62+
```
63+
64+
## Prerrequisitos
65+
66+
**Configuración de tenant:**
67+
68+
```powershell
69+
# Solo para usuarios externos: verificar B2B Direct Connect
70+
Connect-MgGraph -Scopes "Policy.Read.All"
71+
Get-MgPolicyCrossTenantAccessPolicyDefault
72+
```
73+
74+
**Módulos PowerShell necesarios:**
75+
76+
```powershell
77+
# Instalar Microsoft.Graph (módulo principal)
78+
Install-Module -Name Microsoft.Graph -Scope CurrentUser
79+
80+
# Si solo necesitas Teams, puedes instalar el submódulo específico
81+
Install-Module Microsoft.Graph.Teams -Scope CurrentUser
82+
83+
# Verificar instalación
84+
Get-Module Microsoft.Graph* -ListAvailable
85+
```
86+
87+
**Permisos necesarios:**
88+
89+
- `ChannelMember.ReadWrite.All` (application o delegated)
90+
- Permisos de propietario del canal compartido
91+
92+
## Obtener usuarios desde un chat existente
93+
94+
Si ya tienes los usuarios en un chat de Teams, puedes exportar la lista:
95+
96+
### Opción 1: Desde Teams UI
97+
98+
1. Abre el chat en Teams
99+
2. Haz clic en los participantes (icono de personas arriba)
100+
3. Copia manualmente los nombres y emails
101+
102+
### Opción 2: PowerShell (más eficiente)
103+
104+
```powershell
105+
# Instalar módulo si no lo tienes
106+
Install-Module -Name Microsoft.Graph -Scope CurrentUser
107+
108+
# Listar chats donde participas
109+
Connect-MgGraph -Scopes "Chat.Read"
110+
$Chats = Get-MgUserChat -UserId "[email protected]" -All
111+
112+
# Ver detalles de un chat específico (usa Topic para identificarlo)
113+
$Chats | Select-Object Id, Topic, ChatType | Format-Table
114+
115+
# Obtener miembros de un chat específico
116+
$ChatId = "TU_CHAT_ID"
117+
$ChatMembers = Get-MgChatMember -ChatId $ChatId
118+
119+
# Exportar a CSV
120+
$ChatMembers | ForEach-Object {
121+
$Member = Get-MgUser -UserId $_.UserId -ErrorAction SilentlyContinue
122+
if ($Member) {
123+
[PSCustomObject]@{
124+
DisplayName = $Member.DisplayName
125+
UPN = $Member.UserPrincipalName
126+
Role = "" # Ajustar manualmente si necesitas owners
127+
}
128+
}
129+
} | Export-Csv -Path ".\members_from_chat.csv" -NoTypeInformation
130+
131+
Write-Host "CSV generado: members_from_chat.csv"
132+
```
133+
134+
## Formato del archivo CSV
135+
136+
Crea un archivo `members.csv` con esta estructura (puedes generarlo desde el chat como se explicó arriba):
137+
138+
```csv
139+
DisplayName,UPN,Role
140+
Juan Pérez,[email protected],
141+
María García,[email protected],owner
142+
Carlos López,[email protected],
143+
Ana Torres,[email protected],
144+
```
145+
146+
```
147+
148+
**Campos:**
149+
150+
- `DisplayName`: Nombre completo del usuario
151+
- `UPN`: User Principal Name
152+
- **Usuarios internos**: `[email protected]`
153+
- **Usuarios externos**: `[email protected]`
154+
- `Role`: Vacío para miembros normales, `owner` para propietarios
155+
156+
!!! tip "UPN vs Email"
157+
Usa el UPN exacto de Entra ID. Si un usuario externo tiene email diferente al UPN, usa el UPN.
158+
159+
## Script PowerShell completo
160+
161+
```powershell
162+
# Variables de configuración
163+
$TeamId = "YOUR_TEAM_ID"
164+
$ChannelId = "YOUR_CHANNEL_ID"
165+
$CsvPath = ".\members.csv"
166+
167+
# Conectar a Microsoft Graph
168+
Connect-MgGraph -Scopes "ChannelMember.ReadWrite.All"
169+
170+
# Importar CSV
171+
$Members = Import-Csv -Path $CsvPath
172+
173+
# Contadores para reporte
174+
$SuccessCount = 0
175+
$ErrorCount = 0
176+
$ErrorLog = @()
177+
178+
# Procesar cada miembro
179+
foreach ($Member in $Members) {
180+
try {
181+
# Construir objeto de miembro
182+
$MemberParams = @{
183+
"@odata.type" = "#microsoft.graph.aadUserConversationMember"
184+
"[email protected]" = "https://graph.microsoft.com/v1.0/users('$($Member.UPN)')"
185+
}
186+
187+
# Asignar rol si es owner
188+
if ($Member.Role -eq "owner") {
189+
$MemberParams["roles"] = @("owner")
190+
}
191+
192+
# Añadir miembro al canal
193+
New-MgTeamChannelMember -TeamId $TeamId `
194+
-ChannelId $ChannelId `
195+
-BodyParameter $MemberParams
196+
197+
Write-Host "✅ Añadido: $($Member.DisplayName) ($($Member.UPN))" -ForegroundColor Green
198+
$SuccessCount++
199+
200+
} catch {
201+
$ErrorMessage = $_.Exception.Message
202+
Write-Host "❌ Error: $($Member.DisplayName) - $ErrorMessage" -ForegroundColor Red
203+
$ErrorCount++
204+
205+
$ErrorLog += [PSCustomObject]@{
206+
DisplayName = $Member.DisplayName
207+
UPN = $Member.UPN
208+
Error = $ErrorMessage
209+
}
210+
}
211+
}
212+
213+
# Resumen final
214+
Write-Host "`n=== RESUMEN ===" -ForegroundColor Cyan
215+
Write-Host "Total procesados: $($Members.Count)"
216+
Write-Host "Éxitos: $SuccessCount" -ForegroundColor Green
217+
Write-Host "Errores: $ErrorCount" -ForegroundColor Red
218+
219+
# Exportar log de errores si existen
220+
if ($ErrorLog.Count -gt 0) {
221+
$ErrorLog | Export-Csv -Path ".\errors_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv" -NoTypeInformation
222+
Write-Host "`nLog de errores guardado en: errors_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
223+
}
224+
225+
# Desconectar
226+
Disconnect-MgGraph
227+
```
228+
229+
## Obtener TeamId y ChannelId
230+
231+
**Listar equipos:**
232+
233+
```powershell
234+
Get-MgTeam | Select-Object DisplayName, Id
235+
```
236+
237+
**Listar canales de un equipo:**
238+
239+
```powershell
240+
Get-MgTeamChannel -TeamId "TEAM_ID" | Select-Object DisplayName, Id, MembershipType
241+
```
242+
243+
!!! note "Identificar canales compartidos"
244+
Los canales compartidos tienen `MembershipType = "shared"`
245+
246+
## Errores comunes y soluciones
247+
248+
| Error | Causa | Solución |
249+
|-------|-------|----------|
250+
| `User not found` | UPN incorrecto o usuario no existe | Verificar UPN exacto en Entra ID (interno o externo) |
251+
| `Forbidden` | Falta B2B Direct Connect (solo externos) | Configurar cross-tenant access settings |
252+
| `Guest users cannot be added` | Intentas añadir un guest user | Solo B2B Direct Connect; los guests no son compatibles |
253+
| `Insufficient privileges` | Permisos insuficientes | Necesitas ser owner del canal + permisos Graph API |
254+
| `Already a member` | Usuario ya existe en el canal | Normal si reejecutas el script, puedes ignorar |
255+
256+
## Verificar usuarios añadidos
257+
258+
```powershell
259+
# Listar todos los miembros del canal compartido
260+
Get-MgTeamChannelMember -TeamId $TeamId -ChannelId $ChannelId |
261+
Select-Object DisplayName, Email, Roles, UserId
262+
```
263+
264+
## Alternativa: Usar Add-MgTeamChannelAllMember
265+
266+
Para añadir múltiples usuarios en una **única llamada API** (más eficiente):
267+
268+
```powershell
269+
# Construir array de miembros
270+
$AllMembers = @()
271+
foreach ($Member in $Members) {
272+
$MemberObject = @{
273+
"@odata.type" = "#microsoft.graph.aadUserConversationMember"
274+
"[email protected]" = "https://graph.microsoft.com/v1.0/users('$($Member.UPN)')"
275+
"roles" = if ($Member.Role -eq "owner") { @("owner") } else { @() }
276+
}
277+
$AllMembers += $MemberObject
278+
}
279+
280+
# Añadir todos en una sola operación
281+
$BodyParams = @{
282+
values = $AllMembers
283+
}
284+
285+
Invoke-MgGraphRequest -Method POST `
286+
-Uri "https://graph.microsoft.com/v1.0/teams/$TeamId/channels/$ChannelId/members/add" `
287+
-Body ($BodyParams | ConvertTo-Json -Depth 10)
288+
```
289+
290+
!!! tip "Cuándo usar cada método"
291+
- `New-MgTeamChannelMember`: Control granular + logging detallado por usuario
292+
- `Add-MgTeamChannelAllMember`: Máxima velocidad para grandes volúmenes (batching)
293+
294+
## Buenas prácticas
295+
296+
1. **Exportar desde chat existente**: Si ya tienes los usuarios en un chat, usa el script PowerShell para generar el CSV automáticamente
297+
2. **Validar UPNs antes de ejecutar**: Verifica que todos los UPNs existen (internos y externos)
298+
3. **Procesar en lotes pequeños**: Si tienes >100 usuarios, divide el CSV
299+
4. **Guardar logs de errores**: Usa el `-ErrorLog` del script para auditoría
300+
5. **B2B Direct Connect solo para externos**: Los usuarios internos no necesitan configuración adicional
301+
6. **No asumas UPN = Email**: Muchos tenants usan UPNs diferentes al email principal
302+
303+
## Referencias
304+
305+
- [Shared channels in Microsoft Teams](https://learn.microsoft.com/en-us/microsoftteams/shared-channels)
306+
- [Microsoft Graph - Add members to channel](https://learn.microsoft.com/en-us/graph/api/channel-post-members)
307+
- [Get chat members - Microsoft Graph](https://learn.microsoft.com/en-us/graph/api/chat-list-members)
308+
- [B2B Direct Connect documentation](https://learn.microsoft.com/en-us/entra/external-id/b2b-direct-connect-overview)
309+
- [Configure cross-tenant access settings](https://learn.microsoft.com/en-us/entra/external-id/cross-tenant-access-settings-b2b-direct-connect)

0 commit comments

Comments
 (0)