Thiết lập Microsoft Azure để di chuyển nâng cao

Hãy làm theo các bước sau để tạo ứng dụng Microsoft Azure trong cổng thông tin Azure, hỗ trợ di chuyển dữ liệu an toàn từ Exchange Online (Microsoft 365) sang tài khoản Google Workspace của bạn. Bạn có thể chọn một trong hai phương thức:

Sử dụng tập lệnh PowerShell để thiết lập kết nối tự động

Bạn phải là quản trị viên có vai trò toàn cầu hoặc vai trò đặc quyền để hoàn tất các bước này.

Trước khi bắt đầu: Bạn phải cài đặt Install-Module Microsoft.Graph -Scope CurrentUser.

Cách 1: Sử dụng Azure Cloud Shell

  1. Với tư cách quản trị viên, hãy đăng nhập vào cổng thông tin Microsoft Azure.
  2. Nhấp vào Cloud Shellsau đóPowershell.
  3. Nếu được nhắc, hãy tạo một tài khoản lưu trữ và chấp nhận các chế độ cài đặt mặc định.
  4. Dán lệnh Install-Module Microsoft.Graph -Scope CurrentUser rồi nhấp vào Enter.
  5. Nếu bạn thấy lời nhắc cài đặt từ Kho lưu trữ không đáng tin cậy, hãy nhập Y rồi nhấp vào Enter.
  6. Sao chép khối mã bên dưới, dán vào PowerShell rồi nhấp vào Enter.
        <#
        .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. Ghi lại thông tin đăng nhập sau đây và lưu trữ thông tin đó một cách an toàn. Nếu thông tin đăng nhập bị rò rỉ, tin tặc có thể truy cập vào tất cả dữ liệu Exchange Online của bạn.
    • Mật khẩu ứng dụng
    • Mã ứng dụng (ứng dụng khách)
    • Mã thư mục (máy thuê)

Cách 2: Sử dụng Windows PowerShell

  1. Trong Windows, hãy tạo một tệp văn bản thuần tuý mới có tên là migration_app_creator.ps1.
  2. Sao chép khối mã bên dưới, dán vào tệp mới rồi nhấp vào Run with Powershell (Chạy bằng Powershell).
  3.     <#
        .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"
        
  4. Ghi lại thông tin đăng nhập sau đây và lưu trữ thông tin đó một cách an toàn. Nếu thông tin đăng nhập bị rò rỉ, tin tặc có thể truy cập vào tất cả dữ liệu Exchange Online của bạn.
    • Mật khẩu ứng dụng
    • Mã ứng dụng (ứng dụng khách)
    • Mã thư mục (máy thuê)

Sử dụng Azure AD để thiết lập kết nối thủ công

Các bước cụ thể của Microsoft có thể khác nhau tuỳ thuộc vào phiên bản cổng thông tin Azure và các bản cập nhật do Microsoft thực hiện. Hãy tham khảo tài liệu của Microsoft để biết hướng dẫn mới nhất về việc đăng ký và uỷ quyền cho ứng dụng.

Bước 1: Đăng ký ứng dụng mới

Vì lý do bảo mật, bạn nên đăng ký ứng dụng mới dưới dạng một máy thuê.

  1. Với tư cách quản trị viên, hãy đăng nhập vào cổng thông tin Microsoft Azure.
  2. Trong Azure Active Directory (Azure AD), hãy chuyển đến App registrations (Đăng ký ứng dụng).
  3. Nhấp vào New Registration (Đăng ký mới) rồi nhập tên cho ứng dụng của bạn (ví dụ: Enterprise Migration App).
  4. Đối với Supported account types (Các loại tài khoản được hỗ trợ), hãy nhấp vào Accounts in this organizational directory only (Chỉ các tài khoản trong thư mục tổ chức này) để tạo ứng dụng một máy thuê.
  5. Nhấp vào Register (Đăng ký).

Bước 2: Định cấu hình quyền API

Chọn một trong các tùy chọn bên dưới:

Cách 1: Thêm quyền theo cách thủ công

  1. Trong bảng điều hướng bên trái, đối với Manage (Quản lý), hãy nhấp vào API permissions (Quyền API).
  2. Nhấp vào Add a permission (Thêm quyền)sau đóMicrosoft APIs (API của Microsoft)sau đóMicrosoft Graph.
  3. Đối với application permissions (quyền ứng dụng), hãy chọn:
    • calendars.read
    • mail.read
    • contacts.read
    • Directory.read.all
  4. Nhấp vào Grant admin consent for [Your organization] (Cấp quyền đồng ý của quản trị viên cho [Tổ chức của bạn]).

Cách 2: Chỉnh sửa tệp kê khai ứng dụng

  1. Mở tệp kê khai ứng dụng.
  2. Đối với “resourceAccess” : [ ], hãy sao chép và dán khối mã bên dưới.

    Nếu “resourceAccess” : [ ] đã có giá trị, hãy thêm dấu phẩy rồi dán khối mã.

            
            { "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. Nhấp vào Grant admin consent for [Your organization] (Cấp quyền đồng ý của quản trị viên cho [Tổ chức của bạn]).

Bước 3: Tạo mật khẩu ứng dụng

  1. Trong bảng điều hướng bên trái, đối với Manage (Quản lý), hãy nhấp vào Certificates & secrets (Chứng chỉ và khoá bí mật)sau đóNew client secret (Khoá bí mật ứng dụng mới).
  2. Nhập nội dung mô tả, chọn thời gian hết hạn rồi nhấp vào Add (Thêm).
  3. Sao chép Client secret value (Giá trị mật khẩu ứng dụng) và lưu trữ thông tin đó một cách an toàn. Giá trị này chỉ hiển thị một lần.

Bước 4: Thu thập thông tin đăng nhập ứng dụng

Nhấp vào Overview (Tổng quan) rồi ghi lại thông tin đăng nhập sau đây một cách an toàn:

  • Mã ứng dụng (ứng dụng khách)
  • Mã thư mục (máy thuê)


Google, Google Workspace và những nhãn hiệu cũng như biểu tượng có liên quan là nhãn hiệu của Google LLC. Tất cả các tên sản phẩm và công ty khác là nhãn hiệu của những công ty mà chúng liên kết.