Configura la aplicación de Azure para una migración avanzada

Sigue estos pasos para crear una aplicación de Microsoft Azure en el portal de Azure. Debes crear la aplicación para garantizar una migración de datos segura de Microsoft Exchange Online a tus cuentas de Google Workspace. Puedes elegir uno de estos 2 métodos:

Usa una secuencia de comandos de PowerShell para configurar una conexión automática

Debes ser administrador global o administrador de roles con privilegios para completar estos pasos.

Opción 1: Usa Azure Cloud Shell

  1. Como administrador, accede al portal de Azure.
  2. Haz clic en Cloud Shelly luegoPowershell.
  3. Si se te solicita, crea una cuenta de almacenamiento y acepta la configuración predeterminada.
  4. Para crear la aplicación, ingresa el siguiente comando y, luego, haz clic en Intro:

    Install-Module Microsoft.Graph -Scope CurrentUser

  5. Si ves un mensaje para instalar desde un repositorio no confiable, ingresa Y y, luego, haz clic en Intro.
  6. Copia el siguiente bloque de código, pégalo en PowerShell y haz clic en Intro.
        <#
        .SYNOPSIS
        Automates the creation of a Single-Tenant Entra ID App for Workspace Migration.
        Strictly forces account selection and verifies specific Admin roles.
        #>
    
        # Check if the module is missing
        if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Authentication)) {
        Write-Host "Microsoft Graph module is NOT installed." -ForegroundColor Yellow
        $UserResponse = Read-Host "Would you like to try installing Microsoft Graph? (Y/N)"
    
        if ($UserResponse -ieq "Y") {
            try {
                # Use only native cmdlets, no .NET property setting
                Install-Module -Name Microsoft.Graph -Scope CurrentUser -Force -AllowClobber
                Write-Host "Installation complete!" -ForegroundColor Green
            }
            catch {
                Write-Error "Policy is blocking installation. Please contact IT to install Microsoft.Graph module."
                Read-Host "Press Enter to exit"; exit
            }
        }
        else {
            exit
        }
        } else {
        Write-Host "Microsoft Graph modules detected. Proceeding..." -ForegroundColor Green
        }
    
        # --- STEP 0: THE "DEEP" LOGOUT ---
        Write-Host "Forcing session cleanup..." -ForegroundColor Gray
        Disconnect-MgGraph -ErrorAction SilentlyContinue
    
        # Force clear the local token cache folder if it exists
        $CachePath = "$env:USERPROFILE\.mg"
        if (Test-Path $CachePath) {
        try { Remove-Item $CachePath -Recurse -Force -ErrorAction SilentlyContinue } catch {}
        }
    
        Write-Host "Opening Microsoft Login... (Please select the correct account)" -ForegroundColor Cyan
    
        $RequiredScopes = @(
        "Application.ReadWrite.All", 
        "AppRoleAssignment.ReadWrite.All", 
        "Directory.Read.All", 
        "RoleManagement.Read.Directory"
        )
    
        try {
        # In v2, -ContextScope Process is the most reliable way to force account selection
        # and prevent the session from saving to the machine permanently.
        Connect-MgGraph -Scopes $RequiredScopes -ContextScope Process
    
         $Context = Get-MgContext
        if ($null -eq $Context) { throw "Login was cancelled or failed." }
    
        $UserPrincipal = $Context.Account
        Write-Host "Logged in as: $UserPrincipal" -ForegroundColor Green
    
        # --- ROLE VALIDATION ---
        Write-Host "Verifying Directory Roles..." -ForegroundColor Gray
        $UserRoles = Get-MgUserMemberOf -UserId $Context.Account -All | Where-Object { $_.AdditionalProperties.displayName -ne $null }
        
        $Authorized = $false
        $RequiredRoles = @("Global Administrator", "Privileged Role Administrator")
    
        foreach ($role in $UserRoles) {
            $roleName = $role.AdditionalProperties.displayName
            if ($roleName -in $RequiredRoles) {
                $Authorized = $true
                Write-Host "Access Granted: $roleName" -ForegroundColor Green
                break
            }
        }
    
        if (-not $Authorized) {
            Write-Host "`nCRITICAL ERROR: Insufficient Privileges." -ForegroundColor Red
    
         Write-Host "Account must be 'Global Administrator' or 'Privileged Role Administrator'." -ForegroundColor Yellow
            Disconnect-MgGraph
            Read-Host "`nPress Enter to exit"; exit
        }
    
        } catch {
        Write-Error "Login failed: $_"
        Read-Host "Press Enter to exit"; exit
        }
    
        # --- USER INPUT ---
        Write-Host "`n--- APPLICATION SETUP ---" -ForegroundColor Cyan
        $InputName = Read-Host "Enter the name for your new Entra ID Application (Default: Workspace Migration App)"
        $AppName = if ([string]::IsNullOrWhiteSpace($InputName)) { "Workspace Migration App" } else { $InputName }
    
        # --- CONFIGURATION ---
        $PermissionMap = @{
        "calendar.read"  = "Calendars.Read"     
        "mail.read"      = "Mail.Read"
        "contacts.read"  = "Contacts.Read"
        "directory.read" = "Directory.Read.All"
        }
    
        $TenantId = $Context.TenantId
        $GraphAppId = "00000003-0000-0000-c000-000000000000"
    
        try {
        # --- STEP 1: REGISTER APPLICATION ---
        Write-Host "Creating Application: $AppName..." -ForegroundColor Cyan
        $Application = New-MgApplication -BodyParameter @{
            displayName = $AppName
            signInAudience = "AzureADMyOrg"
        }
        
        # --- STEP 2: PREPARE SERVICE PRINCIPAL ---
        $NewServicePrincipal = New-MgServicePrincipal -BodyParameter @{ appId = $Application.AppId }
    
        Write-Host "Waiting 10 seconds for replication..." -ForegroundColor DarkGray
        Start-Sleep -Seconds 10
    
        # --- STEP 3: CONFIGURE & GRANT PERMISSIONS ---
        Write-Host "Configuring API Permissions & Granting Admin Consent..." -ForegroundColor Cyan
        $GraphSP = Get-MgServicePrincipal -Filter "AppId eq '$GraphAppId'" | Select-Object -First 1
        
        $ResourceAccessList = @()
    
        foreach ($key in $PermissionMap.Keys) {
            $RealRoleName = $PermissionMap[$key]
            $Role = $GraphSP.AppRoles | Where-Object { $_.Value -eq $RealRoleName }
    
            if ($Role) {
                $ResourceAccessList += @{ id = $Role.Id; type = "Role" }
    
                New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $NewServicePrincipal.Id -BodyParameter @{
                    principalId = $NewServicePrincipal.Id
                    resourceId  = $GraphSP.Id
                    appRoleId   = $Role.Id
                } | Out-Null
                Write-Host " - Granted: $RealRoleName" -ForegroundColor Gray
            }
        }
    
        Update-MgApplication -ApplicationId $Application.Id -RequiredResourceAccess @(@{
            resourceAppId  = $GraphAppId
            resourceAccess = $ResourceAccessList
        })
    
        # --- STEP 4: CREATE CLIENT SECRET ---
        Write-Host "Generating Client Secret..." -ForegroundColor Cyan
        $ExpiryDate = (Get-Date).AddYears(2).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
        $PasswordCred = Add-MgApplicationPassword -ApplicationId $Application.Id -BodyParameter @{
            passwordCredential = @{
                displayName = "MigrationToolSecret"
                endDateTime = $ExpiryDate
            }
        }
    
        # --- OUTPUT ---
        Write-Host "`n-------------------------------------------------------" -ForegroundColor Yellow
        Write-Host "        SETUP COMPLETE - SAVE THESE DETAILS" -ForegroundColor Yellow
        Write-Host "-------------------------------------------------------" -ForegroundColor Yellow
        Write-Host "Application Name        : $AppName"
        Write-Host "Application (Client) ID : $($Application.AppId)"
        Write-Host "Client Secret Value     : $($PasswordCred.SecretText)"
        Write-Host "Directory (Tenant) ID   : $TenantId"
        Write-Warning "IMPORTANT: Copy the Client Secret Value immediately."
    
        }
        catch {
        Write-Error "Operation failed: $_"
        }
    
        # --- FINAL DISCONNECT ---
        Disconnect-MgGraph
        Read-Host "`nPress Enter to close this window"
        
  7. Anota las siguientes credenciales y almacénalas de forma segura. Si se filtran las credenciales, los hackers podrían acceder a todos tus datos de Exchange Online.
    • Secreto del cliente
    • ID de app (cliente)
    • ID de directorio (tenant)

Opción 2: Usa Windows PowerShell

  1. En Windows, crea un archivo de texto sin formato nuevo y asígnale el nombre migration_app_creator.ps1.
  2. Copia el siguiente bloque de código, pégalo en el archivo nuevo y haz clic en Ejecutar con Powershell.
    <#
    .SYNOPSIS
    Automates the creation of a Single-Tenant Entra ID App for Workspace Migration.
    Strictly forces account selection and verifies specific Admin roles.
    #>

    # Check if the module is missing
    if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Authentication)) {
    Write-Host "Microsoft Graph module is NOT installed." -ForegroundColor Yellow
    $UserResponse = Read-Host "Would you like to try installing Microsoft Graph? (Y/N)"

    if ($UserResponse -ieq "Y") {
        try {
            # Use only native cmdlets, no .NET property setting
            Install-Module -Name Microsoft.Graph -Scope CurrentUser -Force -AllowClobber
            Write-Host "Installation complete!" -ForegroundColor Green
        }
        catch {
            Write-Error "Policy is blocking installation. Please contact IT to install Microsoft.Graph module."
            Read-Host "Press Enter to exit"; exit
        }
    }
    else {
        exit
    }
    } else {
    Write-Host "Microsoft Graph modules detected. Proceeding..." -ForegroundColor Green
    }

    # --- STEP 0: THE "DEEP" LOGOUT ---
    Write-Host "Forcing session cleanup..." -ForegroundColor Gray
    Disconnect-MgGraph -ErrorAction SilentlyContinue

    # Force clear the local token cache folder if it exists
    $CachePath = "$env:USERPROFILE\.mg"
    if (Test-Path $CachePath) {
    try { Remove-Item $CachePath -Recurse -Force -ErrorAction SilentlyContinue } catch {}
    }

    Write-Host "Opening Microsoft Login... (Please select the correct account)" -ForegroundColor Cyan

    $RequiredScopes = @(
    "Application.ReadWrite.All", 
    "AppRoleAssignment.ReadWrite.All", 
    "Directory.Read.All", 
    "RoleManagement.Read.Directory"
    )

    try {
    # In v2, -ContextScope Process is the most reliable way to force account selection
    # and prevent the session from saving to the machine permanently.
    Connect-MgGraph -Scopes $RequiredScopes -ContextScope Process

     $Context = Get-MgContext
    if ($null -eq $Context) { throw "Login was cancelled or failed." }

    $UserPrincipal = $Context.Account
    Write-Host "Logged in as: $UserPrincipal" -ForegroundColor Green

    # --- ROLE VALIDATION ---
    Write-Host "Verifying Directory Roles..." -ForegroundColor Gray
    $UserRoles = Get-MgUserMemberOf -UserId $Context.Account -All | Where-Object { $_.AdditionalProperties.displayName -ne $null }
    
    $Authorized = $false
    $RequiredRoles = @("Global Administrator", "Privileged Role Administrator")

    foreach ($role in $UserRoles) {
        $roleName = $role.AdditionalProperties.displayName
        if ($roleName -in $RequiredRoles) {
            $Authorized = $true
            Write-Host "Access Granted: $roleName" -ForegroundColor Green
            break
        }
    }

    if (-not $Authorized) {
        Write-Host "`nCRITICAL ERROR: Insufficient Privileges." -ForegroundColor Red

     Write-Host "Account must be 'Global Administrator' or 'Privileged Role Administrator'." -ForegroundColor Yellow
        Disconnect-MgGraph
        Read-Host "`nPress Enter to exit"; exit
    }

    } catch {
    Write-Error "Login failed: $_"
    Read-Host "Press Enter to exit"; exit
    }

    # --- USER INPUT ---
    Write-Host "`n--- APPLICATION SETUP ---" -ForegroundColor Cyan
    $InputName = Read-Host "Enter the name for your new Entra ID Application (Default: Workspace Migration App)"
    $AppName = if ([string]::IsNullOrWhiteSpace($InputName)) { "Workspace Migration App" } else { $InputName }

    # --- CONFIGURATION ---
    $PermissionMap = @{
    "calendar.read"  = "Calendars.Read"     
    "mail.read"      = "Mail.Read"
    "contacts.read"  = "Contacts.Read"
    "directory.read" = "Directory.Read.All"
    }

    $TenantId = $Context.TenantId
    $GraphAppId = "00000003-0000-0000-c000-000000000000"

    try {
    # --- STEP 1: REGISTER APPLICATION ---
    Write-Host "Creating Application: $AppName..." -ForegroundColor Cyan
    $Application = New-MgApplication -BodyParameter @{
        displayName = $AppName
        signInAudience = "AzureADMyOrg"
    }
    
    # --- STEP 2: PREPARE SERVICE PRINCIPAL ---
    $NewServicePrincipal = New-MgServicePrincipal -BodyParameter @{ appId = $Application.AppId }

    Write-Host "Waiting 10 seconds for replication..." -ForegroundColor DarkGray
    Start-Sleep -Seconds 10

    # --- STEP 3: CONFIGURE & GRANT PERMISSIONS ---
    Write-Host "Configuring API Permissions & Granting Admin Consent..." -ForegroundColor Cyan
    $GraphSP = Get-MgServicePrincipal -Filter "AppId eq '$GraphAppId'" | Select-Object -First 1
    
    $ResourceAccessList = @()

    foreach ($key in $PermissionMap.Keys) {
        $RealRoleName = $PermissionMap[$key]
        $Role = $GraphSP.AppRoles | Where-Object { $_.Value -eq $RealRoleName }

        if ($Role) {
            $ResourceAccessList += @{ id = $Role.Id; type = "Role" }

            New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $NewServicePrincipal.Id -BodyParameter @{
                principalId = $NewServicePrincipal.Id
                resourceId  = $GraphSP.Id
                appRoleId   = $Role.Id
            } | Out-Null
            Write-Host " - Granted: $RealRoleName" -ForegroundColor Gray
        }
    }

    Update-MgApplication -ApplicationId $Application.Id -RequiredResourceAccess @(@{
        resourceAppId  = $GraphAppId
        resourceAccess = $ResourceAccessList
    })

    # --- STEP 4: CREATE CLIENT SECRET ---
    Write-Host "Generating Client Secret..." -ForegroundColor Cyan
    $ExpiryDate = (Get-Date).AddYears(2).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ")
    $PasswordCred = Add-MgApplicationPassword -ApplicationId $Application.Id -BodyParameter @{
        passwordCredential = @{
            displayName = "MigrationToolSecret"
            endDateTime = $ExpiryDate
        }
    }

    # --- OUTPUT ---
    Write-Host "`n-------------------------------------------------------" -ForegroundColor Yellow
    Write-Host "        SETUP COMPLETE - SAVE THESE DETAILS" -ForegroundColor Yellow
    Write-Host "-------------------------------------------------------" -ForegroundColor Yellow
    Write-Host "Application Name        : $AppName"
    Write-Host "Application (Client) ID : $($Application.AppId)"
    Write-Host "Client Secret Value     : $($PasswordCred.SecretText)"
    Write-Host "Directory (Tenant) ID   : $TenantId"
    Write-Warning "IMPORTANT: Copy the Client Secret Value immediately."

    }
    catch {
    Write-Error "Operation failed: $_"
    }

    # --- FINAL DISCONNECT ---
    Disconnect-MgGraph
    Read-Host "`nPress Enter to close this window"
    
  • Anota las siguientes credenciales y almacénalas de forma segura. Si se filtran las credenciales, los hackers podrían acceder a todos tus datos de Exchange Online.
    • Secreto del cliente
    • ID de app (cliente)
    • ID de directorio (tenant)
  • Usa Azure Active Directory para configurar una conexión manual

    Los pasos específicos de Microsoft pueden variar según la versión del portal de Azure y las actualizaciones que realice Microsoft. Consulta la documentación de Microsoft para obtener la guía más reciente sobre el registro y la autorización de aplicaciones.

    Paso 1: Registra una aplicación nueva

    Por motivos de seguridad, te recomendamos que registres la aplicación nueva como un solo tenant.

    1. Como administrador, accede al portal de Azure.
    2. En Azure Active Directory (Azure AD), ve a Registros de apps.
    3. Haz clic en Nuevo registro y, luego, ingresa un nombre para tu aplicación (por ejemplo, Advanced migration app).
    4. En Tipos de cuentas compatibles, haz clic en Cuentas en este directorio de la organización solo para crear una aplicación de un solo tenant.
    5. Haz clic en Registrar.

    Paso 2: Configura los permisos de API

    Elige una de las siguientes opciones:

    Opción 1: Agrega permisos de forma manual

    1. En el lateral, en Administrar, haz clic en Permisos de API.
    2. Haz clic en Agregar un permisoy luegoAPIs de Microsofty luegoMicrosoft Graph.
    3. En permisos de aplicación, selecciona lo siguiente:
      • calendars.read
      • mail.read
      • contacts.read
      • Directory.read.all
    4. Haz clic en Otorgar consentimiento del administrador para tu organización.

    Opción 2: Edita el manifiesto de la aplicación

    1. Abre el manifiesto de la aplicación.
    2. Ve a “resourceAccess” : [ ]y elige una opción:
      • Si “resourceAccess” : [ ] ya tiene un valor, agrega una coma y, luego, pega el siguiente bloque de código.
      • Si “resourceAccess” : [ ] no tiene un valor, copia y pega el siguiente bloque de código.

      { "id": "089fe4d0-434a-44c5-8827-41ba8a0b17f5", "type": "Role" },

      { "id": "810c84a8-4a9e-49e6-bf7d-12d183f40d01", "type": "Role" },

      { "id": "7ab1d382-f21e-4acd-a863-ba3e13f7da61", "type": "Role" },

      { "id": "798ee544-9d2d-430c-a058-570e29e34338", "type": "Role" }

    3. Haz clic en Otorgar consentimiento del administrador para tu organización.

    Paso 3: Genera el secreto del cliente

    1. En el lateral, en Administrar, haz clic en Certificados y secretosy luegoNuevo secreto del cliente.
    2. Ingresa una descripción, selecciona un período de vencimiento y haz clic en Agregar.
    3. Copia el valor del secreto del cliente y almacénalo de forma segura. El valor se muestra solo una vez.

    Paso 4: Recopila las credenciales de la aplicación

    Importante: Almacena las credenciales de la aplicación de forma segura. Si se filtran las credenciales, los hackers podrían acceder a todos tus datos de Exchange.

    Haz clic en Descripción general y anota de forma segura las siguientes credenciales:

    • ID de app (cliente)
    • ID de directorio (tenant)


    Google, Google Workspace y las marcas y los logotipos relacionados son marcas comerciales de Google LLC. Todos los demás nombres de productos y empresas son marcas comerciales de las empresas con las que se encuentran asociados.