Exchange Online PowerShell: conexión, comandos y ejemplos

Exchange Online PowerShell administra buzones como este: Outlook en la web con el calendario de abril abierto, el botón New event y la opción Add calendar, en la pantalla de un portátil

Exchange Online PowerShell es la forma de administrar el correo de Microsoft 365 con comandos, en lugar de hacerlo con clics en el centro de administración. Con una línea se revisan los permisos de cien buzones, se encuentra un correo perdido o se prepara la salida de un empleado sin olvidar ningún paso. Esta guía explica qué es, cómo instalar el módulo, cómo conectarse a Exchange Online y qué comandos de Exchange Online usa a diario un administrador. Además, incluye escenarios completos, el seguimiento de mensajes y una lista de errores con su solución.

Está escrita para dos lectores. Si usted no es de sistemas, las primeras secciones le explican qué hace esta herramienta y por qué su equipo de TI la usa. En cambio, si administra Microsoft 365, encontrará los comandos listos para copiar, con sus límites y sus trampas.

No copiamos el manual sin más. Comprobamos cada comando y cada parámetro contra la referencia oficial de Microsoft. Además, revisamos el módulo en un equipo de trabajo real, y ahí apareció lo que la documentación no cuenta: el mismo equipo tenía cinco copias del módulo y cada consola cargaba una versión distinta.

Qué es Exchange Online PowerShell y para qué sirve

Exchange Online es el servicio de correo, calendarios y contactos de Microsoft 365. Cada buzón de Outlook de una empresa vive allí. Por su parte, PowerShell es la consola de comandos de Microsoft, la que explicamos en nuestra guía de PowerShell.

Exchange Online PowerShell une las dos cosas. Es un conjunto de comandos, llamados cmdlets, que hablan directamente con el servicio de correo de su organización. Microsoft los distribuye en un módulo gratuito llamado ExchangeOnlineManagement.

Para entenderlo sin tecnicismos, piense en un edificio de oficinas. El centro de administración es la recepción: cómoda y visual, pero atiende de a una persona. En cambio, Exchange Online PowerShell es la llave maestra con la lista de todas las puertas. Con ella se abre, se revisa o se cambia lo que haga falta, en un buzón o en mil.

Sirve, sobre todo, para cinco trabajos:

  • Consultar: quién tiene acceso a qué buzón, cuánto ocupa cada uno o qué reglas tiene.
  • Cambiar muchos buzones a la vez, con la misma orden y sin errores de digitación.
  • Hacer ajustes que el panel no muestra, o que muestra a medias.
  • Investigar qué pasó con un correo y quién cambió una configuración.
  • Automatizar tareas que se repiten, como un informe mensual.

Por qué conviene frente al centro de administración

El centro de administración de Exchange sigue siendo útil. Sin embargo, tiene tres límites claros: trabaja de a un objeto, no deja registro reutilizable de lo que se hizo y esconde muchas opciones. Por eso, los administradores combinan las dos herramientas.

TareaCentro de administraciónExchange Online PowerShell
Dar acceso a un buzón compartidoSencillo, de a una personaUna línea, para una persona o para una lista
Revisar los permisos de todos los buzonesAbriendo uno por unoUn informe en un archivo CSV
Buscar reenvíos de correo hacia fueraNo hay una vista que los reúnaUn filtro sobre todos los buzones
Seguimiento de mensajes de 90 díasSí, con formularioSí, y se puede repetir y guardar
Repetir la misma tarea el mes siguienteVolver a hacer cada clicEjecutar el mismo script
Opciones avanzadas de calendarios, protocolos y reglasParcialesCompletas

En resumen, el panel sirve para el caso suelto. Exchange Online PowerShell sirve para lo que se repite, para lo masivo y para lo que hay que poder demostrar después.

Si todavía no conoce el panel, empiece por nuestra guía del centro de administración de Microsoft 365. Allí se crean los usuarios y se asignan las licencias que luego administra esta consola.

Exchange Online PowerShell no es el Shell de administración de Exchange

Conviene no confundirlos, porque los resultados de búsqueda los mezclan. El Shell de administración de Exchange es la consola de los servidores Exchange instalados en la propia empresa. En cambio, Exchange Online PowerShell administra el correo en la nube de Microsoft 365.

Muchos comandos se llaman igual, como Get-Mailbox o Set-Mailbox. Sin embargo, no todos existen en los dos lados ni aceptan los mismos parámetros. Por eso, antes de copiar un ejemplo de internet, compruebe en la referencia de Microsoft que diga «Exchange Online» en su línea de aplicabilidad.

Requisitos de Exchange Online PowerShell

Para usar Exchange Online PowerShell hacen falta cuatro cosas: una cuenta con permisos, una versión de PowerShell compatible, la directiva de ejecución correcta y el propio módulo. Ninguna exige comprar nada adicional.

Permisos: qué rol necesita en Exchange Online

La cuenta con la que se conecta decide qué comandos ve. Microsoft lo controla con permisos por funciones, conocidos como RBAC. Por ejemplo, un administrador de Exchange puede hacerlo todo. En cambio, un lector global solo puede consultar.

Para el día a día no hace falta ser administrador global. De hecho, Microsoft recomienda usar el rol con menos privilegios que permita hacer la tarea. Una cuenta que solo revisa informes puede tener el grupo de funciones «View-Only Organization Management», que solo consulta.

Si un comando no aparece después de conectarse, casi siempre es por permisos. Este par de órdenes dice qué funciones permiten usarlo y a quién están asignadas:

$roles = Get-ManagementRole -Cmdlet Add-MailboxPermission
$roles | ForEach-Object { Get-ManagementRoleAssignment -Role $_.Name -Delegating $false | Format-Table -AutoSize Role, RoleAssigneeType, RoleAssigneeName }

Versión de PowerShell que pide cada versión del módulo

El módulo funciona en Windows PowerShell 5.1, la que trae Windows, y en PowerShell 7. Sin embargo, cada versión del módulo exige un PowerShell 7 mínimo. Esta tabla resume lo que publica Microsoft en su página sobre el módulo para Windows 11 y Windows Server:

Versión del móduloWindows PowerShell 5.1PowerShell 7
3.10.0 o posterior (junio de 2026)Sí7.6.0 o posterior
3.5.0 a 3.9.2Sí7.4.0 o posterior
3.0.0 a 3.4.0Sí7.2.0 a 7.3.7

En la 5.1, el módulo necesita .NET Framework 4.7.2, que ya viene en Windows 11 y en Windows 10 desde la versión 1803. En macOS y Linux funciona con PowerShell 7. Sin embargo, allí no está disponible la conexión de Seguridad y Cumplimiento, Connect-IPPSSession.

La versión estable al escribir esta guía es la 3.10.1, publicada el 24 de julio de 2026. La Galería de PowerShell registra más de 74 millones de descargas del módulo.

Directiva de ejecución

PowerShell no ejecuta scripts de fábrica en los equipos con Windows. Si intenta conectarse así, verá un error que dice que la ejecución de scripts está deshabilitada en el sistema. Microsoft indica fijar la directiva en RemoteSigned. Para hacerlo solo en su usuario, sin abrir la consola como administrador:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

En nuestra guía de PowerShell explicamos qué hace cada directiva y por qué no conviene dejar Unrestricted.

Cómo instalar el módulo de Exchange Online

El módulo de Exchange Online está en la Galería de PowerShell. Para instalarlo solo en su usuario, sin permisos de administrador, basta con esta línea:

Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser

Si es la primera vez que instala un módulo, PowerShell preguntará si confía en la galería. Responda «Sí». Además, las conexiones necesitan los módulos PowerShellGet y PackageManagement, que Windows 11 ya trae.

Para actualizarlo, use el mismo ámbito con el que lo instaló:

Update-Module -Name ExchangeOnlineManagement -Scope CurrentUser

Si lo instaló para todos los usuarios, abra la consola como administrador y quite -Scope CurrentUser. En cambio, si lo instaló solo para usted, la carpeta del módulo queda dentro de Documentos.

Lo que encontramos en un equipo real: cinco copias del módulo

Antes de escribir los ejemplos, revisamos un portátil de trabajo con Windows 11 que ya usaba el módulo. Lo hicimos en solo lectura y sin conectarnos a ninguna organización. Este fue el resultado:

CopiaDónde estabaTamañoQuién la usa
3.10.1Documentos del usuario, carpeta de PowerShell 763,8 MBPowerShell 7
3.9.2Documentos del usuario, carpeta de PowerShell 755,9 MBNadie: queda tapada por la 3.10.1
3.9.2Archivos de programa, para todos los usuarios55,9 MBNadie, aunque es la más nueva de la 5.1
3.8.0Documentos del usuario, carpeta de Windows PowerShell54,1 MBWindows PowerShell 5.1
3.7.2Documentos del usuario, carpeta de Windows PowerShell54,3 MBNadie

Tres hallazgos que valen para cualquier empresa

Los contamos y después mostramos cómo revisarlos en su equipo.

Primero, cada consola cargaba una versión distinta. PowerShell 7 cargaba la 3.10.1. Sin embargo, Windows PowerShell 5.1 cargaba la 3.8.0, aunque había una 3.9.2 instalada para todos los usuarios. La razón es el orden de búsqueda: PowerShell mira primero la carpeta del usuario y se queda con la versión más alta que encuentra allí. Por tanto, actualizar el módulo para todos no cambia nada si queda una copia vieja en Documentos.

Segundo, las copias viejas no constaban como instaladas. Get-InstalledModule en la 5.1 solo conocía la 3.9.2. Las copias 3.7.2 y 3.8.0 no las había registrado PowerShellGet, así que Update-Module nunca las tocaría. Hay que borrarlas a mano.

Tercero, la carpeta Documentos estaba dentro de OneDrive. Así, las copias del usuario se sincronizaban con la nube: unos 228 MB solo en módulos. Además, de los 216 archivos de las dos copias de la 5.1, 186 estaban «solo en línea». El módulo cargó porque había internet y OneDrive los descargó al vuelo. Sin conexión, la carga habría fallado. Si quiere entender cómo funciona eso, lo explicamos en la guía para sincronizar OneDrive.

Cómo revisar las copias del módulo en su equipo

Estas dos líneas muestran qué copias ve su consola y cuáles registró PowerShellGet:

Get-Module -ListAvailable ExchangeOnlineManagement | Format-Table Version, ModuleBase
Get-InstalledModule ExchangeOnlineManagement -AllVersions | Format-Table Version, InstalledLocation

Y esta dice cuál está usando de verdad, después de cargarlo:

Import-Module ExchangeOnlineManagement
(Get-Module ExchangeOnlineManagement).Version

Para quitar una versión que sí registró PowerShellGet, indique cuál:

Uninstall-Module -Name ExchangeOnlineManagement -RequiredVersion 3.9.2

Las que no aparecen en Get-InstalledModule se borran eliminando su carpeta, con la consola cerrada. Nuestra recomendación es dejar una sola copia por versión de PowerShell, actualizada y en una ruta que no dependa de OneDrive.

Cómo conectarse a Exchange Online

Para conectarse a Exchange Online se usa Connect-ExchangeOnline con su cuenta de administrador, como indica la guía de conexión de Microsoft. Se abre la ventana de inicio de sesión de Microsoft, con su verificación en dos pasos si la tiene activada:

Connect-ExchangeOnline -UserPrincipalName admin@contoso.com -ShowBanner:$false

En los ejemplos usamos contoso.com, el dominio de ejemplo de Microsoft. Cámbielo por el de su empresa. La opción -ShowBanner:$false solo oculta el mensaje de bienvenida.

Para comprobar que la conexión funciona, Microsoft sugiere pedir los dominios aceptados. Además, Get-ConnectionInformation dice con qué cuenta y con qué organización está conectado:

Get-AcceptedDomain
Get-ConnectionInformation | Format-List UserPrincipalName, TenantID, State

Medimos un detalle útil: sin conexión, Get-ConnectionInformation no devuelve nada, ni siquiera un error. Por tanto, un script puede usarlo para saber si debe conectarse antes de seguir.

Otras formas de conectarse

En PowerShell 7 hay dos métodos más. Con -Device, la consola muestra un código y usted inicia sesión desde el navegador de otro equipo o del teléfono. Es útil en servidores sin navegador.

Connect-ExchangeOnline -Device

Ojo: en nuestro equipo, -Device e -InlineCredential no existían en Windows PowerShell 5.1. Solo aparecen en PowerShell 7.

Si su empresa trabaja con un proveedor, el técnico del proveedor puede conectarse a su organización con su propia cuenta y permisos delegados. Así no hace falta prestarle una cuenta de administrador de la empresa:

Connect-ExchangeOnline -UserPrincipalName tecnico@proveedor.com -DelegatedOrganization contoso.onmicrosoft.com

Desconectarse al terminar

Microsoft insiste en cerrar la sesión. Si cierra la ventana sin hacerlo, puede agotar las sesiones disponibles y tendrá que esperar a que caduquen:

Disconnect-ExchangeOnline -Confirm:$false

Errores al conectarse a Exchange Online y su solución

Estos son los mensajes que más aparecen. Los tres primeros los reprodujimos en nuestro equipo, con la consola en español.

MensajeCausaSolución
«You must call Connect-ExchangeOnline before calling any other cmdlet.»Usó un cmdlet Get-EXO* sin conectarseEjecute Connect-ExchangeOnline
El término "Get-Mailbox" no se reconoce como nombre de un cmdlet…Sin conexión, los cmdlets como Get-Mailbox no existen todavíaConéctese: esos cmdlets se cargan al iniciar sesión
No se encuentra un parámetro que coincida con el nombre de parámetro "UseRPSSession"Script antiguo: la versión 3.9.2 retiró ese parámetroBórrelo de la línea de conexión
«Files cannot be loaded because running scripts is disabled on this system»Directiva de ejecución restringidaSet-ExecutionPolicy RemoteSigned -Scope CurrentUser
«Cannot find a cmdlet Update-Manifest» o «Update-ModuleManifest is not recognized»Falta PowerShellGetInstale o actualice PowerShellGet y reabra la consola
Fallos del inicio de sesión de Windows, como «A window handle must be configured»Problemas con el administrador de cuentas web de Windows (WAM)Conéctese con -DisableWAM, disponible desde la 3.7.2
Could not load file or assembly 'System.IdentityModel.Tokens.Jwt'…Choque con otro módulo cargado en la misma ventanaAbra una ventana nueva y conéctese antes de cargar otros módulos

Un detalle del segundo error: confunde a mucha gente. El módulo instalado trae solo 37 comandos, entre ellos los nueve Get-EXO* y los de conexión. El resto, cientos de cmdlets como Get-Mailbox o Set-Mailbox, llega de la nube al conectarse.

Comandos de Exchange Online: cómo leerlos

Todos los cmdlets siguen el patrón verbo-sustantivo. Get consulta, Set cambia, New crea, Add añade y Remove quita. Así, Get-Mailbox consulta buzones y Set-Mailbox los cambia.

Casi todos usan -Identity para decir sobre qué objeto actúan. Acepta el correo, el alias o el nombre. Con el correo completo nunca hay ambigüedad, así que es lo que usamos en esta guía.

Get-EXOMailbox o Get-Mailbox: cuál usar

El módulo trae nueve cmdlets exclusivos que empiezan por Get-EXO. Son versiones rápidas de los clásicos y están pensados para consultar miles de objetos. Por ejemplo, Get-EXOMailbox reemplaza a Get-Mailbox en las consultas.

La diferencia está en las propiedades. Según Microsoft, Get-Mailbox devuelve al menos 230 propiedades por buzón. En cambio, Get-EXOMailbox devuelve un conjunto mínimo y usted pide el resto con -Properties o con -PropertySets. Por eso responde mucho antes.

Cmdlet rápidoCmdlet clásicoPara qué
Get-EXOMailboxGet-MailboxDatos de los buzones
Get-EXOMailboxStatisticsGet-MailboxStatisticsTamaño y número de elementos
Get-EXOMailboxPermissionGet-MailboxPermissionQuién tiene acceso total
Get-EXORecipientPermissionGet-RecipientPermissionQuién puede enviar como
Get-EXOMailboxFolderPermissionGet-MailboxFolderPermissionPermisos de carpetas y calendarios
Get-EXOMailboxFolderStatisticsGet-MailboxFolderStatisticsCarpetas y su tamaño
Get-EXOCasMailboxGet-CASMailboxProtocolos: POP, IMAP, ActiveSync
Get-EXORecipientGet-RecipientCualquier destinatario
Get-EXOMobileDeviceStatisticsGet-MobileDeviceStatisticsTeléfonos conectados

Para cambiar algo se siguen usando los clásicos: Set-Mailbox, Add-MailboxPermission y los demás. Los cmdlets Get-EXO* solo consultan.

La trampa de los 1.000 resultados

Get-EXOMailbox y Get-Mailbox devuelven como máximo 1.000 resultados si no se indica otra cosa. En una empresa grande, un informe puede quedarse corto sin que nadie lo note. Para traerlos todos, añada -ResultSize Unlimited:

Get-EXOMailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox | Select-Object DisplayName, PrimarySmtpAddress, RecipientTypeDetails

Además, filtre en el servidor con -Filter y no después con Where-Object. Así, Exchange solo envía lo que pidió:

Get-EXOMailbox -ResultSize Unlimited -Filter "RecipientTypeDetails -eq 'SharedMailbox'"
Get-EXOMailbox -Identity ana.gomez@contoso.com -PropertySets Delivery, AddressList

Los comandos de Exchange Online más usados

Esta tabla reúne los comandos de Exchange Online que más usa un administrador. Guárdela como referencia rápida; los escenarios de la siguiente sección los combinan.

Buzones y permisos

TareaComando
Listar buzonesGet-EXOMailbox -ResultSize Unlimited
Ver el tamaño de un buzónGet-EXOMailboxStatistics -Identity <correo>
Crear un buzón compartidoNew-Mailbox -Shared -Name <nombre> -PrimarySmtpAddress <correo>
Convertir un buzón en compartidoSet-Mailbox -Identity <correo> -Type Shared
Dar acceso total a un buzónAdd-MailboxPermission -Identity <buzón> -User <persona> -AccessRights FullAccess
Permitir «enviar como»Add-RecipientPermission -Identity <buzón> -Trustee <persona> -AccessRights SendAs
Permitir «enviar en nombre de»Set-Mailbox -Identity <buzón> -GrantSendOnBehalfTo @{Add="<persona>"}
Dar permiso sobre un calendarioAdd-MailboxFolderPermission -Identity <correo>:\<carpeta> -User <persona> -AccessRights Reviewer
Activar la respuesta automáticaSet-MailboxAutoReplyConfiguration -Identity <correo> -AutoReplyState Enabled
Reenviar el correoSet-Mailbox -Identity <correo> -ForwardingAddress <destino>
Ocultar de la libreta de direccionesSet-Mailbox -Identity <correo> -HiddenFromAddressListsEnabled $true
Añadir una dirección de correoSet-Mailbox -Identity <correo> -EmailAddresses @{Add="smtp:<alias>"}
Activar el archivo en líneaEnable-Mailbox -Identity <correo> -Archive

Reglas, grupos, protocolos y seguimiento

TareaComando
Ver las reglas de la bandeja de entradaGet-InboxRule -Mailbox <correo>
Ver los miembros de un grupoGet-DistributionGroupMember -Identity <grupo>
Añadir un miembro a un grupoAdd-DistributionGroupMember -Identity <grupo> -Member <persona>
Desactivar POP e IMAPSet-CASMailbox -Identity <correo> -PopEnabled $false -ImapEnabled $false
Seguimiento de mensajesGet-MessageTraceV2 -SenderAddress <correo>
Ver cambios de los administradoresSearch-UnifiedAuditLog -RecordType ExchangeAdmin

Antes de cambiar algo en muchos buzones, pruebe con uno solo y añada -WhatIf cuando el cmdlet lo admita. Con esa opción, la orden solo muestra lo que haría.

Escenarios de ejemplo con Exchange Online PowerShell

Estos escenarios son los que más se repiten en una mesa de servicio. Cada uno trae los comandos en orden y lo que conviene revisar después.

Inventario de buzones con su tamaño

Es el informe que piden la gerencia o el área de compras antes de renovar licencias. Este script recorre los buzones de personas y los compartidos, pide su tamaño y lo guarda en un CSV que se abre en Excel:

$buzones = Get-EXOMailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox, SharedMailbox
$informe = foreach ($b in $buzones) {
    $e = Get-EXOMailboxStatistics -Identity $b.PrimarySmtpAddress -Properties LastUserActionTime
    [pscustomobject]@{
        Nombre       = $b.DisplayName
        Correo       = $b.PrimarySmtpAddress
        Tipo         = $b.RecipientTypeDetails
        Elementos    = $e.ItemCount
        Tamano       = $e.TotalItemSize
        UltimaAccion = $e.LastUserActionTime
    }
}
$informe | Export-Csv -Path .\buzones.csv -NoTypeInformation -Encoding UTF8

La columna de última acción ayuda a encontrar buzones que nadie usa. Sin embargo, no decida solo con ella: un buzón compartido puede recibir correo a diario aunque nadie lo abra.

Dar acceso a un buzón compartido

Un buzón compartido, como soporte@ o facturacion@, lo usan varias personas sin licencia propia. Para que alguien trabaje en él se le dan hasta tres permisos distintos, y conviene no confundirlos:

PermisoQué permiteCmdlet
Acceso total (FullAccess)Abrir el buzón y leer, mover o borrar sus correosAdd-MailboxPermission
Enviar como (SendAs)Enviar correos que salen con la dirección del buzónAdd-RecipientPermission
Enviar en nombre deEnviar con la leyenda «en nombre de»Set-Mailbox -GrantSendOnBehalfTo
Add-MailboxPermission -Identity soporte@contoso.com -User ana.gomez@contoso.com -AccessRights FullAccess -InheritanceType All -AutoMapping $true
Add-RecipientPermission -Identity soporte@contoso.com -Trustee ana.gomez@contoso.com -AccessRights SendAs -Confirm:$false

Con -AutoMapping $true, que es el valor por defecto, el buzón aparece solo en el Outlook de escritorio de esa persona. Si no lo quiere así, use $false. Microsoft aclara un detalle: para quitar el automapeo a alguien que ya tiene el permiso, hay que retirarle el acceso y volver a dárselo con $false.

Para revisar quién tiene acceso, sin las cuentas internas del sistema:

Get-EXOMailboxPermission -Identity soporte@contoso.com | Where-Object { $_.User -notlike "NT AUTHORITY*" }
Get-EXORecipientPermission -Identity soporte@contoso.com

Y para retirar el acceso total cuando la persona cambia de área:

Remove-MailboxPermission -Identity soporte@contoso.com -User ana.gomez@contoso.com -AccessRights FullAccess -InheritanceType All -Confirm:$false

Tenga en cuenta dos límites que publica Microsoft en su página sobre buzones compartidos. Un buzón compartido admite como máximo 25 personas; con más, conviene un grupo de Microsoft 365. Además, sin licencia guarda hasta 50 GB.

Salida de un empleado: convertir su buzón en compartido

Cuando alguien deja la empresa, su correo no debe perderse ni seguir abierto. La práctica habitual es convertir el buzón en compartido, dejar una respuesta automática y dar acceso a quien recibe sus temas:

$saliente = "carlos.ruiz@contoso.com"
Set-Mailbox -Identity $saliente -Type Shared
Set-MailboxAutoReplyConfiguration -Identity $saliente -AutoReplyState Enabled -InternalMessage "Carlos ya no trabaja en la empresa. Escriba a ventas@contoso.com." -ExternalMessage "Gracias por escribir. Para atender su solicitud, escriba a ventas@contoso.com." -ExternalAudience All
Set-Mailbox -Identity $saliente -HiddenFromAddressListsEnabled $true
Add-MailboxPermission -Identity $saliente -User jefe.ventas@contoso.com -AccessRights FullAccess -InheritanceType All
Get-EXOMailbox -Identity $saliente -Properties RecipientTypeDetails, HiddenFromAddressListsEnabled
Get-EXOMailboxStatistics -Identity $saliente

Antes y después de esos comandos hay cuatro reglas de Microsoft que no conviene saltarse:

  1. El buzón debe tener licencia en el momento de convertirlo. Después, la licencia se puede quitar.
  2. Solo quite la licencia si el buzón ocupa menos de 50 GB. La última línea del bloque lo dice.
  3. Al convertirlo, el usuario y la contraseña originales siguen funcionando. Por tanto, bloquee el inicio de sesión y cambie la contraseña en el centro de administración.
  4. No borre la cuenta del usuario: el buzón compartido la necesita como ancla.

Además, un buzón compartido sin licencia no admite retención por litigio ni archivo ampliado. Si la empresa debe conservar ese correo por obligación legal, mantenga la licencia que corresponda. Y si lo que busca es una copia que se pueda restaurar, eso es otro tema: lo explicamos en nuestra guía de backup de Microsoft 365.

Permisos de calendario: la trampa del nombre de la carpeta

Una petición frecuente es que la asistente gestione el calendario de la gerencia. El cmdlet es Add-MailboxFolderPermission, y casi todos los ejemplos de internet escriben la carpeta así: gerencia@contoso.com:\Calendar.

En un buzón en español, ese ejemplo falla. Las carpetas predeterminadas toman el idioma del buzón, así que la carpeta se llama «Calendario» y no «Calendar». Microsoft lo deja ver en Set-MailboxRegionalConfiguration, que tiene una opción para traducir esos nombres.

La solución es no escribir el nombre a mano, sino pedírselo al buzón:

$cal = (Get-EXOMailboxFolderStatistics -Identity gerencia@contoso.com -Folderscope Calendar | Where-Object FolderType -eq "Calendar").Name
$cal
Get-EXOMailboxFolderPermission -Identity "gerencia@contoso.com:\$cal"
Add-MailboxFolderPermission -Identity "gerencia@contoso.com:\$cal" -User asistente@contoso.com -AccessRights Editor -SharingPermissionFlags Delegate

Editor permite crear, cambiar y borrar citas. Con -SharingPermissionFlags Delegate, además, la asistente recibe las convocatorias para aceptarlas o rechazarlas. Si solo debe ver la agenda, use Reviewer.

Para el resto de la empresa existen dos niveles intermedios, propios de los calendarios. AvailabilityOnly muestra solo libre u ocupado. En cambio, LimitedDetails añade el asunto y el lugar. Para cambiar lo que ve todo el mundo, se modifica el usuario Default:

Set-MailboxFolderPermission -Identity "gerencia@contoso.com:\$cal" -User Default -AccessRights LimitedDetails

Reenvío de correo y por qué a veces no llega

Para reenviar el correo de un buzón a otro de la empresa, use -ForwardingAddress. Con -DeliverToMailboxAndForward $true se guarda además una copia en el buzón original; sin él, el correo solo llega al destino:

Set-Mailbox -Identity carlos.ruiz@contoso.com -ForwardingAddress ventas@contoso.com -DeliverToMailboxAndForward $true

El reenvío hacia fuera de la empresa es otra historia. Microsoft bloquea por defecto el reenvío automático externo desde 2021 en las organizaciones nuevas y en las que no lo usaban. Lo controla la directiva de correo no deseado saliente. Cuando bloquea, el remitente recibe este rebote: «5.7.520 Access denied, Your organization does not allow external forwarding».

Por eso, antes de configurar un reenvío externo, mire la directiva:

Get-HostedOutboundSpamFilterPolicy | Format-Table Name, AutoForwardingMode

El valor Automatic es ambiguo, porque se comporta distinto según la organización. Microsoft recomienda fijar On u Off de forma explícita.

Encontrar reenvíos ocultos

Un reenvío que nadie recuerda es un riesgo. Puede ser un ajuste viejo o una regla creada por un atacante que entró en la cuenta, una técnica que describimos en nuestra guía sobre phishing. Este informe lista los buzones que reenvían:

Get-EXOMailbox -ResultSize Unlimited -Properties ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward | Where-Object { $_.ForwardingAddress -or $_.ForwardingSmtpAddress } | Select-Object DisplayName, ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward

Los usuarios también reenvían con reglas de la bandeja de entrada, que no aparecen en el informe anterior. Para revisarlas en un buzón:

Get-InboxRule -Mailbox ana.gomez@contoso.com | Where-Object { $_.ForwardTo -or $_.ForwardAsAttachmentTo -or $_.RedirectTo } | Format-List Name, Enabled, ForwardTo, ForwardAsAttachmentTo, RedirectTo

Desactivar POP, IMAP y SMTP autenticado

POP e IMAP son protocolos antiguos que casi nadie necesita en una empresa con Outlook. Dejarlos activos amplía la superficie de ataque sin aportar nada. Primero, mire quién los tiene encendidos:

Get-EXOCasMailbox -ResultSize Unlimited -PropertySets Minimum, Pop, Imap | Where-Object { $_.PopEnabled -or $_.ImapEnabled } | Select-Object DisplayName, PopEnabled, ImapEnabled

Después, apáguelos en los buzones que no los usan. La misma orden puede desactivar el envío SMTP autenticado, salvo en el buzón de una impresora o de una aplicación que envíe correo:

Set-CASMailbox -Identity ana.gomez@contoso.com -PopEnabled $false -ImapEnabled $false -SmtpClientAuthenticationDisabled $true

Grupos de distribución

Para ver los miembros de un grupo y para añadir una lista desde un CSV con una columna llamada «Correo»:

Get-DistributionGroupMember -Identity ventas@contoso.com -ResultSize Unlimited | Select-Object DisplayName, PrimarySmtpAddress
Import-Csv .\nuevos.csv | ForEach-Object { Add-DistributionGroupMember -Identity ventas@contoso.com -Member $_.Correo }

Microsoft advierte un límite de las conexiones actuales: cada cmdlet tiene 15 minutos para terminar. Por eso, una operación masiva sobre miles de miembros debe partirse en tandas.

Seguimiento de mensajes en Exchange Online con Get-MessageTraceV2

El seguimiento de mensajes responde la pregunta más común de la mesa de servicio: «me dicen que me enviaron un correo y no me llegó». Muestra si el mensaje entró, a quién se entregó y con qué estado.

El cmdlet actual es Get-MessageTraceV2. El antiguo Get-MessageTrace está reemplazado y Microsoft anuncia que se retirará. Por eso, si tiene scripts con el nombre viejo, cámbielos ya.

Get-MessageTraceV2 -SenderAddress proveedor@externo.com -StartDate (Get-Date).AddDays(-3) -EndDate (Get-Date) | Format-Table Received, SenderAddress, RecipientAddress, Subject, Status

Si el estado no es «Delivered», pida el detalle del recorrido:

$m = Get-MessageTraceV2 -RecipientAddress ana.gomez@contoso.com -Subject "Factura" -SubjectFilterType Contains -StartDate (Get-Date).AddDays(-2) -EndDate (Get-Date)
$m | Get-MessageTraceDetailV2 | Format-Table Date, Event, Detail

Límites del seguimiento de mensajes

Estos son sus límites, según la referencia de Get-MessageTraceV2:

LímiteValor
Historial disponibleÚltimos 90 días
Sin fechasSolo las últimas 48 horas
Rango por consultaHasta 10 días
Resultados1.000 de fábrica, 5.000 como máximo con -ResultSize
RitmoHasta 100 consultas en cinco minutos
Hora de los resultadosUTC: en Colombia, cinco horas más que la hora local

Dos consejos que evitan resultados vacíos. Primero, pase las fechas como objetos, como en los ejemplos, y no como texto. Si escribe la fecha como texto, el cmdlet la interpreta con el formato regional del equipo, y el 03/10 puede ser marzo u octubre. Segundo, recuerde que la hora del resultado está en UTC.

Revisar los 90 días completos

Para revisar los 90 días hay que partir el rango en tramos de 10 días. Este bucle lo hace solo:

$fin = Get-Date
$inicio = $fin.AddDays(-90)
$todo = for ($d = $inicio; $d -lt $fin; $d = $d.AddDays(10)) {
    $hasta = if ($d.AddDays(10) -lt $fin) { $d.AddDays(10) } else { $fin }
    Get-MessageTraceV2 -SenderAddress proveedor@externo.com -StartDate $d -EndDate $hasta -ResultSize 5000
}
$todo.Count

Son nueve consultas, muy por debajo del límite de 100 cada cinco minutos.

Registro de auditoría: quién cambió qué en Exchange Online

Cuando algo cambia sin aviso, como un permiso nuevo o un reenvío, el registro de auditoría unificado dice quién lo hizo. Esta consulta trae las acciones de los administradores en Exchange durante la última semana:

Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -RecordType ExchangeAdmin -ResultSize 5000 | Select-Object CreationDate, UserIds, Operations

Y esta se limita a dos operaciones concretas:

Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -Operations Set-Mailbox, Add-MailboxPermission -ResultSize 5000 | Select-Object CreationDate, UserIds, Operations, AuditData

Ojo con un límite: sin -ResultSize, devuelve solo 100 registros. El máximo por consulta es 5.000. Para más, Microsoft indica usar -SessionCommand ReturnLargeSet, que llega a 50.000 registros sin ordenar.

Automatizar Exchange Online PowerShell sin contraseña

Un informe que corre cada noche no puede esperar a que alguien escriba la contraseña. Tampoco conviene guardar una contraseña en un archivo. Para eso existe la autenticación de solo aplicación, que se conecta con un certificado.

Los pasos, según la guía de autenticación de solo aplicación, son cinco:

  1. Registrar una aplicación en Microsoft Entra ID.
  2. Darle el permiso Exchange.ManageAsApp, de «Office 365 Exchange Online», con consentimiento del administrador.
  3. Crear un certificado.
  4. Subir la parte pública del certificado a la aplicación.
  5. Asignar a la aplicación un rol. Para solo leer, basta con Lector global.

El certificado se puede crear en el propio equipo, en una consola elevada:

$cert = New-SelfSignedCertificate -DnsName "contoso.com" -CertStoreLocation "Cert:\CurrentUser\My" -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange
$cert | Export-Certificate -FilePath .\automatizacion.cer

Con todo listo, la conexión ya no pide nada. Use el dominio .onmicrosoft.com de su organización:

Connect-ExchangeOnline -CertificateThumbprint $cert.Thumbprint -AppId "00000000-0000-0000-0000-000000000000" -Organization "contoso.onmicrosoft.com" -ShowBanner:$false

Cambie los ceros por el identificador de su aplicación. Además, anote la fecha de vencimiento: el certificado del ejemplo dura un año, y el día que caduca el script deja de conectarse.

Recomendaciones para trabajar con Exchange Online PowerShell

Estas son las prácticas que nos parecen más útiles, sacadas de la documentación de Microsoft y del laboratorio:

  • Use una cuenta con el rol justo. No haga informes con un administrador global.
  • Pruebe en un buzón antes de aplicar a todos. Y use -WhatIf cuando el cmdlet lo admita.
  • Exporte antes de cambiar. Un CSV con el estado previo es su forma de deshacer.
  • Pida solo las propiedades que necesita. Evite -PropertySets All, que según Microsoft hace la consulta más lenta y menos fiable.
  • Filtre en el servidor. -Filter es más rápido que traer todo y filtrar con Where-Object.
  • Use -ResultSize Unlimited en los informes. Si no, se quedan en 1.000 resultados.
  • Pase las fechas como objetos. Así no depende del formato regional del equipo.
  • Mantenga una sola copia del módulo por consola. Y revise qué versión carga de verdad, como en nuestro laboratorio.
  • Desconéctese al terminar. Y en scripts largos, limite los cmdlets con -CommandName, porque Microsoft advierte que conectar y desconectar muchas veces en la misma sesión puede provocar una fuga de memoria.
  • Restrinja la consola a quien la necesita. Microsoft permite quitar el acceso a usuarios que no administran, con Set-User -EXOModuleEnabled $false. Hágalo de forma selectiva, nunca a todos a la vez, o puede dejar fuera a los propios administradores.

Este es el ejemplo de conexión limitada a tres cmdlets, útil en una tarea programada:

Connect-ExchangeOnline -UserPrincipalName admin@contoso.com -CommandName Get-EXOMailbox, Get-MessageTraceV2, Set-Mailbox -ShowBanner:$false

Lo que no probamos

Una guía honesta dice dónde termina su laboratorio:

  • No nos conectamos a ninguna organización real. Revisamos el módulo instalado y validamos cada cmdlet y cada parámetro contra la referencia oficial de Microsoft.
  • Por tanto, las salidas de los comandos remotos, como Get-Mailbox o Get-MessageTraceV2, no las vimos en pantalla. Los límites que citamos son los publicados por Microsoft.
  • No probamos la autenticación de solo aplicación ni las identidades administradas de Azure.
  • No probamos el módulo en Linux ni en macOS.

Lo que sí medimos lo hicimos en Windows 11, con Windows PowerShell 5.1 y PowerShell 7.6.6, sin permisos de administrador.

Cuándo conviene delegar la administración del correo

Exchange Online PowerShell resuelve en minutos lo que en el panel lleva horas. Sin embargo, el correo de una empresa no se administra solo con comandos. Alguien tiene que revisar los permisos cada mes, cerrar los buzones de quienes se van y dejar escrito cada cambio.

En KHARONTE, ese trabajo forma parte de la administración de Microsoft 365 de nuestra línea de gestión de plataformas: usuarios, licencias, buzones y accesos. Cada solicitud entra por nuestra mesa de ayuda TI, queda registrada y se resuelve con su trazabilidad.

Si además quiere delegar los servidores, las redes y el soporte de los puestos de trabajo, todo eso entra en nuestros servicios administrados de TI. Puede ver el alcance completo en la página de servicios de TI para empresas.

Preguntas frecuentes sobre Exchange Online PowerShell

¿Qué es Exchange Online PowerShell?

Es el conjunto de comandos de PowerShell que administra el correo de Microsoft 365. Se instala con el módulo gratuito ExchangeOnlineManagement y se conecta con Connect-ExchangeOnline.

¿Cómo me conecto a Exchange Online?

Instale el módulo con Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser y ejecute Connect-ExchangeOnline -UserPrincipalName con su cuenta. Se abrirá la ventana de inicio de sesión de Microsoft.

¿Necesito una licencia especial?

No. El módulo es gratuito. Lo que necesita es una cuenta con un rol de administración de Exchange o, para solo consultar, un rol de lectura.

¿Por qué no funciona Get-Mailbox?

Casi siempre es porque no se ha conectado. Sin conexión, en nuestro equipo Get-Mailbox respondió que no se reconoce como nombre de un cmdlet. Esos comandos llegan al iniciar sesión.

¿Es mejor Get-EXOMailbox o Get-Mailbox?

Para consultar muchos buzones, Get-EXOMailbox, que es más rápido porque devuelve menos propiedades. Para cambiarlos, se sigue usando Set-Mailbox.

¿Cuántos días de seguimiento de mensajes guarda Exchange Online?

Con Get-MessageTraceV2, los últimos 90 días, en consultas de hasta 10 días cada una.

¿Funciona en Mac y en Linux?

Sí, con PowerShell 7. Sin embargo, la conexión de Seguridad y Cumplimiento, Connect-IPPSSession, no está disponible en esos sistemas.

¿Exchange Online PowerShell es lo mismo que el Shell de administración de Exchange?

No. Ese administra servidores Exchange instalados en la empresa. Exchange Online PowerShell administra el correo en la nube de Microsoft 365, aunque muchos comandos se llamen igual.

Hablemos de la TI de su empresa

Cuéntenos qué necesita su operación y le enviamos una propuesta por escrito. Cada línea del portafolio se contrata por separado.

Compartir este artículo

Últimas entradas

Escríbanos ahora