Migracion de las automatizaciones de alta y baja de usuarios desde Power Automate Desktop (licencia Unattended) a Azure Automation con Hybrid Runbook Worker, eliminando la dependencia de PAD y reduciendo costes en ~100 €/mes.
Power Automate Desktop con licencia Unattended requiere una VM Windows dedicada con sesion activa. Azure Automation elimina esa dependencia y ejecuta los scripts directamente on-prem via Hybrid Worker.
Power Automate Cloud actua de disparador y orquestador. Azure Automation recibe el job y lo despacha al Hybrid Worker on-prem, que ejecuta los scripts con acceso completo a AD, M365 y los sistemas internos.
hybrid-worker/OnOffBoarding/ bajo control de versiones en Bitbucket, y se actualiza en el servidor con un simple git pull. Los wrappers se publican automaticamente en Azure mediante Bitbucket Pipelines al hacer push a master.
El proyecto vive en el repositorio jmfernandez bajo la carpeta hybrid-worker/, sincronizada en el servidor via sparse checkout para no clonar el repo completo.
| Fichero | Descripcion |
|---|---|
runbooks/UserOnboarding.ps1 |
Wrapper de alta: parametros, llama a onboarding.ps1, VM Hyper-V opcional, comentario Jira, JSON output |
runbooks/UserOffboarding.ps1 |
Wrapper de baja: parametros, llama a offboarding.ps1 + remove_license.ps1, comentario Jira, JSON output |
OnOffBoarding/onboarding.ps1 |
Script de alta: 9 pasos (AD, proxyAddresses, extensionAttributes, grupos, AD Connect sync) |
OnOffBoarding/offboarding.ps1 |
Script de baja: 11 pasos (AD disable, M365, Exchange, grupos, licencias, prebajas) |
OnOffBoarding/create_vm.ps1 |
Crea VM en cluster Hyper-V hypervcolt.oficina.idealista, la registra como rol de cluster y la arranca |
OnOffBoarding/remove_license.ps1 |
Busca usuario GitHub via SAML/UPN y elimina licencia Copilot del team idealista_copilot |
OnOffBoarding/config.psd1 |
Credenciales centralizadas: AzureAD, Email SMTP, Jira API token, GitHub token, grupos excluidos |
modules/JiraComments.psm1 |
Modulo PS con Add-JiraComment y New-JiraTicket via Jira REST API v2 con Basic Auth |
README.md |
Guia de deploy paso a paso: sparse checkout, Azure Arc, Hybrid Worker group, publicacion de runbooks |
bitbucket-pipelines.yml |
CI/CD: publica automaticamente los runbooks en Azure Automation al hacer push a master |
hybrid-worker/. Comando de configuracion: git sparse-checkout set hybrid-worker. Actualizacion: git pull origin master.
Crea el usuario en AD clonando un usuario plantilla, sincroniza con M365 y opcionalmente crea una VM en el cluster Hyper-V. Publica el resultado en Jira y devuelve JSON para Power Automate.
| Parametro | Tipo | Descripcion |
|---|---|---|
SourceUserSamAccountName | string * | Usuario plantilla a clonar |
NewSamAccountName | string * | Login del nuevo usuario |
GivenName / Surname | string * | Nombre y apellidos |
PrimarySMTP / SecondarySMTP | string / string[] | Direcciones de correo |
ExtensionAttribute1..15 | string | Atributos extendidos AD |
AdditionalGroups | string[] | Grupos adicionales mas alla de la plantilla |
OU | string[] | OU destino (Azure Automation splitea strings con comas — se rejunta en el wrapper) |
CreateVM | bool | Si true y el alta es exitosa, crea VM en cluster Hyper-V |
Platform | string | Plataforma (Windows / Mac). Determina grupo de licencias M365 via mapeo en config.psd1 |
JiraTicket | string | Ticket donde publicar el comentario de resultado |
success, samAccountName, upn, displayName, password — resultado del proceso de alta en AD y M365.
vmCreated, vmLog — resultado de la creacion de VM en el cluster. Solo presente si CreateVM=true y el alta fue exitosa.
licenseGroupAssigned, licenseAvailable, jiraLicenseTicket — asignacion de grupo de licencias, disponibilidad de SKU y ticket Jira si licencias agotadas.
jiraCommentPosted — indica si el comentario wiki-formatted se publico correctamente en el ticket. Incluye tabla de estado y log completo.
Add-ClusterVirtualMachineRole) escriben warnings directamente al host del proceso, sin pasar por los streams de PowerShell. Para evitar que contaminen el JSON output, create_vm.ps1 escribe el resultado en $env:TEMP\create_vm_result.json y el wrapper lanza el script via Start-Process con stdout/stderr redirigidos a ficheros descartados.
Deshabilita el usuario en AD, revoca sesiones M365, comparte el buzon, elimina licencias y gestiona la cuenta GitHub Copilot. Todo en un unico job con resultado en Jira y JSON para Power Automate.
| Parametro | Tipo | Descripcion |
|---|---|---|
UPN | string * | UPN del usuario a dar de baja |
EnableAutoReply | string * | "True"/"False" — si configurar autorrespuesta en el buzon |
MensajeAutoReply | string | Texto de la autorrespuesta (interno y externo) |
JiraTicket | string | Ticket donde publicar el comentario de resultado |
| Paso | Accion |
|---|---|
| 1 | Deshabilitar cuenta AD |
| 2 | Reset de contrasena aleatoria |
| 3 | Eliminar de todos los grupos AD |
| 4 | Mover OU a Prebajas |
| Paso | Accion |
|---|---|
| 5 | Bloquear sign-in M365 |
| 6 | Revocar sesiones activas |
| 7 | Eliminar grupos M365 |
| 8 | Convertir buzon en compartido |
| 9 | Configurar autorrespuesta |
| 10 | Eliminar licencias M365 |
remove_license.ps1 con el UPN tras el offboarding principal. Busca el GitHub username via GraphQL SAML (paginado), verifica si el usuario esta en el team idealista_copilot y lo elimina. Si el usuario no tiene cuenta GitHub o no tiene licencia, finaliza sin error. El resultado (githubFound, githubUsername, copilotFound, copilotRemoved) se incluye en el JSON output y en el comentario de Jira.
(/) / (x)) y la publica directamente en el ticket via Jira REST API v2 con Basic Auth. No requiere ninguna accion adicional en Power Automate.
La migracion resuelve varios problemas de seguridad que tenia la arquitectura anterior con PAD Unattended.
Todas las credenciales (AzureAD, SMTP, Jira API token, GitHub token) viven en config.psd1 bajo control de versiones. En PAD estaban dispersas en variables de entorno o hardcodeadas en flujos exportados.
La conexion a Azure AD / Microsoft Graph usa autenticacion por certificado (CertificateThumbprint), no credenciales de usuario. El certificado reside en el cert store del servidor on-prem.
El Hybrid Worker ejecuta solo en el servidor on-prem designado. Azure Automation no tiene acceso directo a los recursos internos — solo despacha el job al worker que si tiene ese acceso.
Cada ejecucion genera un log detallado paso a paso que queda registrado en el job de Azure Automation y publicado en el ticket de Jira. Antes, el log de PAD era efimero y dificil de acceder.
Todo el codigo (wrappers + scripts + modulos + config template) esta en Bitbucket. Los cambios son revisables, reversibles y auditables. PAD exporta flujos como JSON binario poco legible.
PAD Unattended requeria una VM Windows con sesion de usuario activa 24/7, un vector de riesgo. El Hybrid Worker es un servicio de Windows que no necesita sesion interactiva.
La migracion elimina la unica licencia de pago del stack de automatizacion.
Licencia Power Automate Unattended RPA por maquina. Requiere ademas una VM Windows dedicada (coste de infraestructura adicional).
Azure Automation incluye 500 minutos de ejecucion gratuitos al mes. El volumen de altas/bajas (~200/año) queda muy por debajo de ese limite. El Hybrid Worker corre en un servidor ya existente.
Los runbooks se publican automaticamente en Azure Automation mediante Bitbucket Pipelines al hacer push a master.
| Cambio | Accion necesaria |
|---|---|
| Logica de onboarding / offboarding | Editar en git + git push + git pull en el servidor. No hay que republicar el runbook. |
| Wrapper (parametros, logica del wrapper) | Editar wrapper en git + push. Bitbucket Pipelines publica automaticamente el runbook en Azure. + git pull en servidor. |
| Credenciales (token Jira, GitHub, etc.) | Editar config.psd1 en git + push + pull en servidor. Sin cambios en Azure. |
| Nuevo modulo PowerShell | Copiar a modules/ en git + push + pull en servidor. Verificar que el modulo esta disponible para el usuario de servicio del Hybrid Worker. |
hybrid-worker/runbooks/ y hybrid-worker/HyperV/, sube el contenido via API REST de Azure y ejecuta az automation runbook publish. Variables de repositorio: AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID.