Mantener enlaces precisos del administrador de cuentas de usuario de Entra ID
Vínculos precisos de usuario-administrador necesarios para muchas características de Microsoft 365
En el pasado, escribí sobre la importancia de estandarizar el proceso de creación de cuentas de usuario para que las propiedades de la cuenta terminen siendo completamente pobladas con propiedades como departamento, gerente, etc. Aunque es relativamente fácil asegurarse de que las propiedades de la cuenta sean precisas cuando se crean, con el tiempo, es casi inevitable que aparezcan imprecisiones a menos que se tomen medidas para validar y corregir errores en los enlaces del administrador de cuentas de usuario de Entra ID. PowerShell es muy útil a este respecto, ya que los scripts para identificar problemas con los datos de la cuenta son fáciles de escribir.
Las relaciones entre directivos y empleados son posiblemente las actualizaciones más difíciles de gestionar. A menudo, los cambios en las líneas jerárquicas se producen sin ningún conocimiento del departamento de TI. Se trata de cuestiones de recursos humanos y, a menos que RR.HH. informe a TI sobre la necesidad de actualizar Entra ID, el directorio permanece intacto y gradualmente desciende a un estado inexacto.
La razón por la que la precisión del directorio es importante es que Microsoft 365 resalta los organigramas en varios lugares, como Teams (Figura 1), la tarjeta de perfil de usuario de Microsoft 365 y el explorador de organizaciones en Outlook para Windows (requiere una licencia de Viva Suite).
Obviamente, si Entra ID contiene información inexacta sobre las relaciones de informes, los gráficos generados por las aplicaciones serán engañosos. Ése es un problema que debería solucionarse.
Las grandes organizaciones tienden a tener sistemas de recursos humanos sofisticados que pueden incluir una fuente a Entra ID para manejar cambios como relaciones de informes, departamentos, números de teléfono, ubicaciones físicas, etc. Pero supongamos que nuestra organización no posee ese tipo de información. En cambio, necesitamos encontrar una manera de replicar lo que podría suceder si una fuente de recursos humanos estuviera disponible.
Definiendo una posible solución
Al esbozar el tipo de solución que podríamos desarrollar, se me ocurrió lo siguiente:
- Recursos Humanos proporciona actualizaciones periódicas de información sobre los gerentes y sus departamentos, incluido el gerente de nivel 2 de cada departamento. Para este ejercicio, usaremos un archivo CSV llamado c:\temp\ManagerData.csv para almacenar estos datos.
- Un script de PowerShell lee la información de recursos humanos y verifica cada cuenta de usuario para actualizar al administrador según el departamento asignado a la cuenta. Si el usuario es el administrador del departamento, el script actualiza la cuenta con el administrador de nivel 2. Debido a que existe la necesidad de alejarnos de los antiguos módulos de Azure AD y MSOL, usaremos cmdlets del SDK de Microsoft Graph PowerShell.
Simple. El script podría ejecutarse de forma interactiva, pero en un entorno de producción, será más probable ejecutarlo de forma programada utilizando algo como un runbook de Azure Automation.
Una solución comercial de mantenimiento de directorios como LiveTiles Directory (que antes se conocía como Hyperfish) hará el trabajo de manera más elegante y completa, pero es más divertido codificar una solución casera. Puedes descargar el script que escribí desde GitHub. Como siempre, los guiones que escribimos tienen como objetivo ilustrar principios en lugar de ser soluciones completamente funcionales. Utilice el script como desee.
Scripting de la solución
El script de ejemplo pasa por varias fases para encontrar cuentas de usuario, determinar el administrador de departamento adecuado para asignar y, finalmente, actualizar las cuentas. Aquí hay una descripción general de lo que sucede.
Primero, el guión lee la información sobre los gerentes de departamento de RRHH. Como los datos están en un archivo CSV, todo lo que se necesita es el cmdlet Import-CSV. Sin embargo, es posible que el script tenga que procesar miles de empleados, por lo que se necesita un acceso rápido a los datos. Por este motivo, el script carga el nombre del departamento y el administrador (nombre principal del usuario) en una tabla hash. Si el script detecta algún error en los datos de administración, marca un error y se detiene.
A continuación, la secuencia de comandos encuentra el conjunto de cuentas de usuario para procesar. Las cuentas de usuario no siempre están asociadas con personas reales que podrían tener un administrador, por lo que para excluir cuentas utilizadas para cosas como salas y buzones compartidos y cuentas de invitados, la secuencia de comandos utiliza una configuración avanzada. Grafique la consulta con Entra ID con el cmdlet Get-MgUser para buscar cuentas con al menos una licencia asignada. Filtrar la salida de Get-MgUser de esta manera es un comando muy útil que probablemente terminarás usando en muchos scripts:
Write-Host "Finding licensed user accounts..."
[array]$Users = Get-MgUser -All -Filter "assignedLicenses/`$count ne 0 and userType eq 'Member'" -ConsistencyLevel eventual -CountVariable UsersFound | Sort-Object DisplayName
If (!($Users)) { Write-Host "Couldn't find any user accounts with assigned licenses!" ; break }
Después de recuperar el conjunto de cuentas de usuario, el script divide las cuentas en aquellas que tienen una propiedad de departamento completa y aquellas que no la tienen. Obviamente, el script sólo puede procesar cuentas con departamentos porque utiliza esa propiedad para encontrar al administrador. Al mismo tiempo, al darse cuenta de que la vida es imperfecta, el script lee un administrador predeterminado para usar cuando no puede coincidir con un departamento:
[array]$UsersNoDepartment = $Users | Where-Object {$Null -eq $_.department}
[array]$UsersWithDepartment = $Users | Where-Object {$Null -ne $_.department}
# Get default manager to assign people to when we can't find a department manager
$DefaultManager = $ManagerData | Where-Object {$_.Department -eq "Default" } | Select-Object -ExpandProperty Manager
La siguiente parte del script se centra en determinar qué administrador asignar a una cuenta de usuario. Si la búsqueda en la tabla hash utilizando el valor del departamento para la cuenta de usuario tiene éxito, sabemos qué administrador asignar. Algunos procesamientos condicionales manejan la situación en la que un usuario es el director del departamento. Este código existe porque Microsoft 365 permite que un usuario sea su propio administrador, algo que no sucede con demasiada frecuencia en la vida real. Existe otro control para la cuenta del CEO, que no tiene un gerente porque está en la cima de la organización.
Después de determinar el administrador que se asignará a una cuenta de usuario, el script verifica si el administrador ya está presente para la cuenta. Para ello, el script ejecuta el cmdlet Get-MgUserManager y compara el valor del nombre principal de usuario del administrador con el nombre principal de usuario del administrador de departamento actual. Si los dos coinciden, el script no intentará actualizar la cuenta.
$UserManager = (Get-MgUserManager -UserId $User.Id -ErrorAction SilentlyContinue).additionalProperties.userPrincipalName
If ($DepartmentManager -eq $UserManager) {
# Same manager, so don't update
$DepartmentManager = $Null
}
El último paso es donde el script llama al cmdlet Set-MgUserManagerByRef para actualizar la cuenta. El cmdlet funciona por referencia, lo que significa que la entrada hace referencia a otro objeto (el administrador del departamento). El cmdlet acepta el objeto de destino identificado por su identificador de objeto o nombre principal de usuario (como se usa en este ejemplo). Esto es lo que hace el código:
Write-Host ("Updating user account {0} with manager {1}" -f $User.displayName, $DepartmentManager)
$ManagerId = ("https://graph.microsoft.com/v1.0/users/{0}" -f $DepartmentManager)
$NewManager = @{"@odata.id"=$ManagerId}
Set-MgUserManagerByRef -UserId $User.Id -BodyParameter $NewManager
Como resultado, el script genera un informe sobre las actualizaciones de gestión que procesa. El script exporta la salida como un archivo CSV y muestra detalles a través del cmdlet Out-GridView (Figura 2).
El script también anota si encuentra cuentas que no tengan una propiedad de departamento.
Un poco más complejo de lo previsto
Cuando comencé a escribir el script de ejemplo, pensé que el código terminaría en unas 40 líneas. El script final es aproximadamente el doble (sin ningún manejo de errores), lo que demuestra nuevamente mi incompetencia al estimar tareas. Saber cómo manejar las tareas de administración con PowerShell es algo bueno. Aparte de cualquier otra cosa, este ejercicio demuestra el uso de los cmdlets Get-MgUserManager y Set-MgUserManagerByRef que podría necesitar para actualizar los scripts que utilizan el futuro módulos obsoletos de AzureAD y MSOL.
Planificación y consolidación de la migración de la plataforma Microsoft
Minimice el riesgo, el tiempo, el costo y la complejidad asociados con su próxima transferencia de dominio de Exchange Online

