← Volver al blog

Altas y bajas de usuarios en Microsoft 365: procedimiento y scripts

Cómo organizar las altas y bajas de usuarios en Microsoft 365 con RRHH, detectar cuentas inactivas con PowerShell y liberar licencias sin perder datos. Ciclo de vida de identidades

Ciclo de vida de identidades en Microsoft 365 con alta, cambio y baja, y un informe de PowerShell de cuentas inactivas con licencia

En muchas empresas, las altas y bajas de usuarios en Microsoft 365 dependen de un correo de Recursos Humanos. A veces llega unos días antes, a veces el mismo día que la persona se incorpora y, en el caso de las bajas, a veces no llega nunca. El resultado es siempre el mismo: nuevos empleados que empiezan sin acceso a sus herramientas y cuentas de personas que ya no están en la empresa, activas y con licencia, durante meses.

Basta con exportar los últimos inicios de sesión del tenant para comprobarlo. Es habitual encontrar decenas de cuentas con licencia asignada que llevan tres, seis o doce meses sin iniciar sesión. Eso es dinero pagado por licencias que nadie usa y, sobre todo, un riesgo de seguridad: cuentas activas sin dueño que nadie vigila.

En esta guía verás cómo resolverlo en dos frentes: un procedimiento de altas, cambios y bajas acordado con RRHH, y los scripts de PowerShell para detectar cuentas inactivas y ejecutar las bajas de forma segura.

El problema no es técnico, es de proceso

Crear o deshabilitar una cuenta lleva minutos. Lo que falla es todo lo que ocurre antes:

  • TI no sabe con antelación que alguien entra, así que la cuenta, las licencias y el equipo se preparan con prisas.
  • Nadie tiene la obligación clara de avisar cuando alguien se va, así que la cuenta sigue activa.
  • Los cambios de puesto no se comunican, y la persona acumula permisos de todos los departamentos por los que pasa.
  • No hay ningún control periódico que detecte los fallos anteriores.

Este ciclo se conoce en el sector como Joiner-Mover-Leaver (alta, cambio y baja), y es uno de los controles básicos de cualquier marco de seguridad, incluido ISO 27001. La solución pasa por definirlo por escrito y repartir responsabilidades.

Paso 1: definir quién hace qué

El punto de partida es acordar con RRHH y con los responsables de área un reparto claro:

Rol Responsabilidad
RRHH Comunicar altas, cambios y bajas con la antelación acordada. Es la fuente oficial de quién trabaja en la empresa.
Responsable del área Indicar qué aplicaciones, carpetas y permisos necesita la persona, y validarlos.
TI Ejecutar el alta o la baja en los sistemas, dentro del plazo acordado, y dejar registro.

Y unos plazos concretos. Por ejemplo:

  • Altas: al menos 5 días hábiles antes de la incorporación.
  • Cambios de puesto: antes de que el cambio sea efectivo.
  • Bajas: en cuanto se conozca la fecha de salida, con el día y la hora en que debe cortarse el acceso.

Estos plazos no son un capricho de TI: con ellos, el primer día de una persona empieza con su equipo, su cuenta y sus accesos listos, y la salida de alguien no deja una puerta abierta.

Paso 2: sustituir el correo por una solicitud estructurada

Un correo libre siempre olvida algo. Lo ideal es que las solicitudes entren por la herramienta de tickets (ServiceNow, GLPI, Jira Service Management…) o, como mínimo, por un formulario, por ejemplo con Microsoft Forms, que obligue a rellenar los datos necesarios.

Datos mínimos para un alta:

  • Nombre completo, puesto, departamento y responsable directo.
  • Fecha y sede de incorporación.
  • Tipo de contrato y, si es temporal, fecha de fin prevista.
  • Equipo necesario (portátil, móvil, periféricos).
  • Aplicaciones, carpetas compartidas y listas de distribución.

Datos mínimos para una baja:

  • Nombre, fecha y hora efectiva de salida.
  • Quién se queda con el correo y con los archivos de OneDrive.
  • Si hace falta respuesta automática o reenvío temporal.
  • Equipos y dispositivos que deben recogerse.

Si la solicitud incluye la fecha de fin de los contratos temporales, TI puede programar la baja por adelantado en lugar de depender de un aviso posterior.

Paso 3: estandarizar las altas

Para que todas las altas sean iguales, conviene trabajar con perfiles por departamento en lugar de copiar los permisos de un compañero.

  • Licencias por grupo. Con el licenciamiento basado en grupos de Entra ID, al añadir a una persona al grupo de su departamento recibe automáticamente la licencia correcta. Requiere Entra ID P1, incluido en Microsoft 365 Business Premium, E3 y E5.
  • Grupos de seguridad por puesto. Los accesos a carpetas, SharePoint y aplicaciones se asignan a grupos, no a personas.
  • Checklist de alta. Cuenta en Active Directory o Entra ID, licencia, MFA, equipo registrado en Intune, grupos y accesos, bienvenida con las instrucciones básicas.

Paso 4: ejecutar las bajas sin perder información

Una baja bien hecha no consiste solo en deshabilitar la cuenta. El orden importa:

  1. Bloquear el inicio de sesión y cerrar las sesiones activas, para que la persona no pueda seguir entrando desde el móvil o el navegador.
  2. Convertir el buzón en buzón compartido si otra persona necesita acceder al correo. Hay que hacerlo antes de quitar la licencia; si no, el buzón se elimina al terminar el periodo de gracia.
  3. Dar acceso a los archivos de OneDrive al responsable, o moverlos a SharePoint, antes de eliminar la cuenta.
  4. Quitar las licencias para liberarlas.
  5. Retirar o borrar el dispositivo desde Intune y recoger el equipo.
  6. Deshabilitar la cuenta en Active Directory y moverla a una unidad organizativa de bajas, si el entorno es híbrido.
  7. Eliminar la cuenta pasado el periodo de conservación que marque la política de la empresa.

Este script automatiza los pasos 1, 2 y 4 para un usuario concreto:

param([Parameter(Mandatory)][string]$Usuario)

Connect-MgGraph -Scopes "User.ReadWrite.All","Directory.ReadWrite.All" -NoWelcome
Connect-ExchangeOnline -ShowBanner:$false

# 1. Bloquear el inicio de sesión y cerrar sesiones activas
Update-MgUser -UserId $Usuario -AccountEnabled:$false
Revoke-MgUserSignInSession -UserId $Usuario | Out-Null

# 2. Convertir el buzón en compartido ANTES de quitar la licencia
Set-Mailbox -Identity $Usuario -Type Shared

# 3. Quitar las licencias asignadas directamente
$licencias = (Get-MgUserLicenseDetail -UserId $Usuario).SkuId
if ($licencias) {
    Set-MgUserLicense -UserId $Usuario -AddLicenses @() -RemoveLicenses $licencias | Out-Null
}

Write-Host "Baja completada para $Usuario" -ForegroundColor Green

Antes de usarlo, ten en cuenta estas limitaciones:

  • Entornos híbridos. Si los usuarios se sincronizan desde Active Directory con Entra Connect, la cuenta se deshabilita en AD, no en Entra ID. En ese caso, sustituye el primer Update-MgUser por Disable-ADAccount y deja que se sincronice.
  • Licencias por grupo. Las licencias heredadas de un grupo no se pueden quitar con Set-MgUserLicense: hay que sacar al usuario del grupo.
  • Buzones compartidos. No necesitan licencia mientras no superen los 50 GB y no tengan archivo ni retención por litigio. Si los tienen, necesitarán licencia.
  • OneDrive sin licencia. Microsoft aplica una política específica a las cuentas de OneDrive que se quedan sin licencia durante un tiempo prolongado. Revísala y no dejes cuentas en ese estado indefinidamente.

Paso 5: controlar periódicamente las cuentas inactivas

Aunque el procedimiento funcione, siempre habrá alguna baja que no se comunique. Por eso hace falta un control periódico que detecte las cuentas con licencia que llevan tiempo sin usarse.

Este script genera un informe de los usuarios con licencia sin inicio de sesión en los últimos días que indiques (90 por defecto). Excluye las cuentas creadas en ese periodo, para no marcar como inactiva a alguien que acaba de incorporarse:

param([int]$Dias = 90)

Connect-MgGraph -Scopes "User.Read.All","AuditLog.Read.All" -NoWelcome
$limite = (Get-Date).AddDays(-$Dias)

# Nombres legibles de las licencias del tenant
$skus = @{}
Get-MgSubscribedSku | ForEach-Object { $skus[$_.SkuId] = $_.SkuPartNumber }

Get-MgUser -All -Property DisplayName,UserPrincipalName,AccountEnabled,CreatedDateTime,AssignedLicenses,SignInActivity |
    Where-Object { $_.AssignedLicenses.Count -gt 0 -and $_.CreatedDateTime -lt $limite } |
    ForEach-Object {
        $fechas = @($_.SignInActivity.LastSignInDateTime,
                    $_.SignInActivity.LastNonInteractiveSignInDateTime) | Where-Object { $_ }
        $ultimo = $fechas | Sort-Object -Descending | Select-Object -First 1

        [PSCustomObject]@{
            Usuario     = $_.UserPrincipalName
            Nombre      = $_.DisplayName
            Habilitada  = $_.AccountEnabled
            UltimoLogin = $ultimo
            Dias        = if ($ultimo) { [int]((Get-Date) - $ultimo).TotalDays } else { 'Nunca' }
            Licencias   = ($_.AssignedLicenses.SkuId | ForEach-Object { $skus[$_] }) -join ', '
        }
    } |
    Where-Object { -not $_.UltimoLogin -or $_.UltimoLogin -lt $limite } |
    Sort-Object UltimoLogin |
    Export-Csv .\cuentas-inactivas.csv -NoTypeInformation -Encoding UTF8

Algunas notas sobre el informe:

  • Para leer los datos de inicio de sesión (SignInActivity) el tenant necesita Entra ID P1 o superior, y la cuenta que ejecuta el script, permisos de lectura de registros de auditoría.
  • El script tiene en cuenta tanto los inicios de sesión interactivos como los no interactivos, que son los que hacen las aplicaciones en segundo plano. Así evitas marcar como inactivo a alguien que solo usa Outlook o Teams sin volver a introducir la contraseña.
  • Una cuenta inactiva no siempre es una baja: puede ser una baja médica, una excedencia o una cuenta de servicio. Por eso el informe no borra nada. Cada caso se valida con RRHH antes de actuar.

Si además tienes Active Directory local, el equivalente es Search-ADAccount:

Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly |
    Where-Object Enabled |
    Select-Object Name, SamAccountName, LastLogonDate |
    Export-Csv .\ad-cuentas-inactivas.csv -NoTypeInformation -Encoding UTF8

Ten en cuenta que el atributo LastLogonDate puede ir hasta unos 14 días por detrás de la realidad, porque no se replica en cada inicio de sesión.

Paso 6: conciliar con RRHH cada mes

El último control, y el más eficaz, es sencillo: una vez al mes, RRHH envía la lista de personas en plantilla y TI la compara con las cuentas activas con licencia. Cualquier cuenta que no esté en la lista de RRHH y no sea una cuenta de servicio documentada se revisa.

Junto con el informe de inactividad, esta conciliación cierra el círculo: el procedimiento evita la mayoría de los errores y los controles periódicos detectan los que se escapan.

Qué se consigue

  • Menos gasto en licencias, porque las que no se usan se detectan y se reasignan.
  • Menos superficie de ataque, al no quedar cuentas activas de personas que ya no están.
  • Incorporaciones sin fricción, con todo preparado desde el primer día.
  • Trazabilidad para auditorías, con cada alta y baja registrada y aprobada.

Preguntas frecuentes

¿Cómo saber qué usuarios de Microsoft 365 no inician sesión? Con Microsoft Graph PowerShell, consultando la propiedad SignInActivity de los usuarios, o desde el centro de administración de Entra ID. Para un informe con licencias y filtros, un script como el de esta guía es lo más práctico.

¿Qué pasa con el correo de un usuario al quitarle la licencia? El buzón se conserva durante un periodo de gracia y después se elimina. Si necesitas mantenerlo, conviértelo en buzón compartido antes de quitar la licencia.

¿Se puede automatizar el alta de usuarios desde RRHH? Sí. Desde un formulario con Power Automate hasta la integración directa del sistema de RRHH con Entra ID. Pero automatizar solo tiene sentido cuando el procedimiento está bien definido.

¿Cada cuánto conviene revisar las cuentas inactivas? Una revisión mensual o trimestral es un buen punto de partida, junto con la conciliación con RRHH.

Conclusión

Las cuentas huérfanas y las licencias desperdiciadas no suelen ser un problema técnico, sino la consecuencia de no tener un procedimiento de altas y bajas. Con responsabilidades claras entre RRHH y TI, solicitudes estructuradas, bajas ejecutadas en el orden correcto y un control periódico de inactividad, el problema pasa de descubrirse por casualidad a estar bajo control.