Migracion completada — Marzo 2026

Azure Automation
+ Hybrid Worker

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.

👤 Autor: JM Fernandez + Claude (Anthropic)
📅 Fecha: Marzo 2026
☁️ Plataforma: Azure Automation + Azure Arc
Azure Automation Hybrid Runbook Worker PowerShell 7.2 Power Automate Cloud Jira REST API v2 GitHub Enterprise API Hyper-V Cluster Azure Arc
~100 €
ahorro mensual
2
runbooks en produccion
5
sistemas integrados
0
licencias PAD necesarias
100%
trazabilidad en Jira

Por que migrar

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.

Antes — PAD Unattended

Power Automate Desktop

  • Licencia Unattended ~100 €/mes por VM
  • VM Windows dedicada con sesion RDP activa
  • Logica mezclada entre flujos PAD y scripts PS
  • Jira gestionado manualmente desde Power Automate
  • Credenciales expuestas en variables de entorno PAD
  • Sin control de versiones del orquestador
  • GitHub Copilot offboarding como paso separado en PAD
Ahora — Azure Automation

Azure Automation + Hybrid Worker

  • Sin licencia adicional (incluido en Azure)
  • Servidor on-prem existente como Hybrid Worker
  • Wrappers ligeros en Azure, logica en git on-prem
  • Jira integrado directamente en los runbooks
  • Credenciales centralizadas en config.psd1
  • Todo bajo control de versiones en Bitbucket
  • GitHub Copilot offboarding integrado en el runbook

Flujo de ejecucion

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.

📋
Jira Trigger
Power Automate Cloud
Nuevo ticket en Jira dispara el flujo de alta o baja.
☁️
Azure Automation
Runbook Job
Crea el job y lo enruta al Hybrid Worker Group correcto.
💻
Hybrid Worker
sisscripts / on-prem
Ejecuta el wrapper PS7 con acceso a AD, M365 y sistemas internos.
UserOnboarding: onboarding.ps1 AD + M365 + Hyper-V VM + Jira comment
UserOffboarding: offboarding.ps1 + remove_license.ps1 AD + M365 + GitHub Copilot + Jira comment
Patron thin wrapper: El runbook subido a Azure es un wrapper minimo. Toda la logica vive en git en el servidor on-prem.
JSON output: Cada runbook emite un JSON plano y estructurado. Power Automate lo parsea con Parse JSON y lo usa para el mensaje de Teams y la condicion de error.
Thin wrapper pattern: El runbook que vive en Azure Automation es deliberadamente minimal: solo declara parametros y llama al script real por ruta absoluta. Toda la logica de negocio permanece en 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.

Estructura del proyecto

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
Sparse checkout: En el servidor on-prem solo se sincroniza la carpeta hybrid-worker/. Comando de configuracion: git sparse-checkout set hybrid-worker. Actualizacion: git pull origin master.

Alta de usuario

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.

ParametroTipoDescripcion
SourceUserSamAccountNamestring *Usuario plantilla a clonar
NewSamAccountNamestring *Login del nuevo usuario
GivenName / Surnamestring *Nombre y apellidos
PrimarySMTP / SecondarySMTPstring / string[]Direcciones de correo
ExtensionAttribute1..15stringAtributos extendidos AD
AdditionalGroupsstring[]Grupos adicionales mas alla de la plantilla
OUstring[]OU destino (Azure Automation splitea strings con comas — se rejunta en el wrapper)
CreateVMboolSi true y el alta es exitosa, crea VM en cluster Hyper-V
PlatformstringPlataforma (Windows / Mac). Determina grupo de licencias M365 via mapeo en config.psd1
JiraTicketstringTicket donde publicar el comentario de resultado

JSON output

Datos del alta

success, samAccountName, upn, displayName, password — resultado del proceso de alta en AD y M365.

💻

VM Hyper-V

vmCreated, vmLog — resultado de la creacion de VM en el cluster. Solo presente si CreateVM=true y el alta fue exitosa.

📋

Licencias M365

licenseGroupAssigned, licenseAvailable, jiraLicenseTicket — asignacion de grupo de licencias, disponibilidad de SKU y ticket Jira si licencias agotadas.

💬

Jira

jiraCommentPosted — indica si el comentario wiki-formatted se publico correctamente en el ticket. Incluye tabla de estado y log completo.

Nota VM Hyper-V: Los cmdlets de Failover Clustering (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.

Baja de usuario

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.

ParametroTipoDescripcion
UPNstring *UPN del usuario a dar de baja
EnableAutoReplystring *"True"/"False" — si configurar autorrespuesta en el buzon
MensajeAutoReplystringTexto de la autorrespuesta (interno y externo)
JiraTicketstringTicket donde publicar el comentario de resultado

Acciones sobre Active Directory

PasoAccion
1Deshabilitar cuenta AD
2Reset de contrasena aleatoria
3Eliminar de todos los grupos AD
4Mover OU a Prebajas

Acciones sobre Microsoft 365

PasoAccion
5Bloquear sign-in M365
6Revocar sesiones activas
7Eliminar grupos M365
8Convertir buzon en compartido
9Configurar autorrespuesta
10Eliminar licencias M365
GitHub Copilot: El wrapper llama a 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.
Resultado en Jira: El wrapper construye una tabla wiki-markup con el estado de cada accion ((/) / (x)) y la publica directamente en el ticket via Jira REST API v2 con Basic Auth. No requiere ninguna accion adicional en Power Automate.

Mejoras de seguridad

La migracion resuelve varios problemas de seguridad que tenia la arquitectura anterior con PAD Unattended.

🔒 Credenciales centralizadas

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.

🔓 Autenticacion por certificado

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.

📍 Perimetro de ejecucion definido

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.

📋 Trazabilidad completa

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.

📄 Control de versiones

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.

🚫 Sin sesion RDP persistente

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.

Reduccion de costes

La migracion elimina la unica licencia de pago del stack de automatizacion.

Antes — PAD Unattended

~100 €/mes

Licencia Power Automate Unattended RPA por maquina. Requiere ademas una VM Windows dedicada (coste de infraestructura adicional).

Ahora — Azure Automation

~0 €/mes

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.

Ahorro anual estimado: ~1.200 € — solo en licencia PAD Unattended, sin contar el coste operativo de mantener la VM Windows dedicada y gestionar las renovaciones de licencia.

Como actualizar

Los runbooks se publican automaticamente en Azure Automation mediante Bitbucket Pipelines al hacer push a master.

CambioAccion 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.
CI/CD: El pipeline de Bitbucket detecta cambios en 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.