ตั้งค่า Microsoft Azure สำหรับการย้ายข้อมูลขั้นสูง

ทำตามขั้นตอนต่อไปนี้เพื่อสร้างแอปพลิเคชัน Microsoft Azure ภายในพอร์ทัล Azure ซึ่งรองรับการย้ายข้อมูลอย่างปลอดภัยจาก Exchange Online (Microsoft 365) ไปยังบัญชี Google Workspace คุณเลือกได้ 2 วิธีดังนี้

ใช้สคริปต์ PowerShell เพื่อตั้งค่าการเชื่อมต่ออัตโนมัติ

คุณต้องเป็นผู้ดูแลระบบที่มีบทบาทส่วนกลางหรือบทบาทที่มีสิทธิ์จึงจะทำตามขั้นตอนเหล่านี้ได้

ก่อนเริ่มต้น: คุณต้องติดตั้ง Install-Module Microsoft.Graph -Scope CurrentUser

ตัวเลือกที่ 1: ใช้ Azure Cloud Shell

  1. ในฐานะผู้ดูแลระบบ ให้ลงชื่อเข้าใช้พอร์ทัล Microsoft Azure
  2. คลิก Cloud Shellจากนั้นPowershell
  3. เมื่อได้รับแจ้ง ให้สร้างบัญชีพื้นที่เก็บข้อมูลและยอมรับการตั้งค่าเริ่มต้น
  4. วางคำสั่ง Install-Module Microsoft.Graph -Scope CurrentUser แล้วคลิก Enter
  5. หากเห็นข้อความแจ้งให้ติดตั้งจากที่เก็บที่ไม่น่าเชื่อถือ ให้พิมพ์ Y แล้วคลิก Enter
  6. คัดลอกบล็อกโค้ดด้านล่าง วางลงใน PowerShell แล้วคลิก 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. โปรดจดบันทึกข้อมูลเข้าสู่ระบบต่อไปนี้และจัดเก็บไว้อย่างปลอดภัย หากข้อมูลเข้าสู่ระบบรั่วไหล แฮ็กเกอร์จะเข้าถึงข้อมูล Exchange Online ทั้งหมดของคุณได้
    • รหัสลับไคลเอ็นต์
    • รหัสแอปพลิเคชัน (ไคลเอ็นต์)
    • รหัสไดเรกทอรี (ผู้เช่า)

ตัวเลือกที่ 2: ใช้ Windows PowerShell

  1. ใน Windows ให้สร้างไฟล์ข้อความธรรมดาใหม่ชื่อ migration_app_creator.ps1
  2. คัดลอกบล็อกโค้ดด้านล่าง วางลงในไฟล์ใหม่ แล้วคลิกเรียกใช้ด้วย 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. โปรดจดบันทึกข้อมูลเข้าสู่ระบบต่อไปนี้และจัดเก็บไว้อย่างปลอดภัย หากข้อมูลเข้าสู่ระบบรั่วไหล แฮ็กเกอร์จะเข้าถึงข้อมูล Exchange Online ทั้งหมดของคุณได้
    • รหัสลับไคลเอ็นต์
    • รหัสแอปพลิเคชัน (ไคลเอ็นต์)
    • รหัสไดเรกทอรี (ผู้เช่า)

ใช้ Azure AD เพื่อตั้งค่าการเชื่อมต่อด้วยตนเอง

ขั้นตอนของ Microsoft อาจแตกต่างกันไปตามเวอร์ชันของพอร์ทัล Azure และการอัปเดตที่ Microsoft ทำ โปรดดูคำแนะนำล่าสุดเกี่ยวกับการจดทะเบียนและการให้สิทธิ์แอปในเอกสารประกอบของ Microsoft

ขั้นตอนที่ 1: จดทะเบียนแอปพลิเคชันใหม่

เราขอแนะนำให้คุณจดทะเบียนแอปพลิเคชันใหม่เป็นกลุ่มผู้ใช้เดียวเพื่อความปลอดภัย

  1. ในฐานะผู้ดูแลระบบ ให้ลงชื่อเข้าใช้พอร์ทัล Microsoft Azure
  2. ใน Azure Active Directory (Azure AD) ให้ไปที่ App registrations
  3. คลิก New Registration แล้วป้อนชื่อแอปพลิเคชัน (เช่น Enterprise Migration App)
  4. สำหรับประเภทบัญชีที่รองรับ ให้คลิกบัญชีในไดเรกทอรีขององค์กรนี้เท่านั้นเพื่อสร้างแอปพลิเคชันแบบผู้เช่ารายเดียว
  5. คลิก Register

ขั้นตอนที่ 2: กำหนดค่าสิทธิ์ API

เลือกตัวเลือกใดตัวเลือกหนึ่งต่อไปนี้

ตัวเลือกที่ 1: เพิ่มสิทธิ์ด้วยตนเอง

  1. คลิก API permissions ในส่วนจัดการในการนําทางด้านซ้าย
  2. คลิก Add a permissionจากนั้นMicrosoft APIsจากนั้นMicrosoft Graph
  3. สำหรับสิทธิ์ของแอปพลิเคชัน ให้เลือกตัวเลือกต่อไปนี้
    • calendars.read
    • mail.read
    • contacts.read
    • Directory.read.all
  4. คลิก Grant admin consent for [Your organization]

ตัวเลือกที่ 2: แก้ไขไฟล์ Manifest ของแอปพลิเคชัน

  1. เปิดไฟล์ Manifest ของแอปพลิเคชัน
  2. สำหรับ "resourceAccess" : [ ] ให้คัดลอกและวางบล็อกโค้ดด้านล่าง

    หาก "resourceAccess" : [ ] มีค่าอยู่แล้ว ให้ใส่คอมมาแล้ววางโค้ดบล็อก

            
            { "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. คลิก Grant admin consent for [Your organization]

ขั้นตอนที่ 3: สร้างรหัสลับไคลเอ็นต์

  1. ในการนำทางด้านซ้าย ให้คลิก Certificates & secretsจากนั้นNew client secret ในส่วนจัดการ
  2. ป้อนคำอธิบาย เลือกระยะเวลาหมดอายุ แล้วคลิกเพิ่ม
  3. คัดลอกค่ารหัสลับไคลเอ็นต์และจัดเก็บอย่างปลอดภัย โดยค่าจะแสดงเพียงครั้งเดียว

ขั้นตอนที่ 4: รวบรวมข้อมูลเข้าสู่ระบบของแอปพลิเคชัน

คลิก Overview แล้วจดบันทึกข้อมูลเข้าสู่ระบบต่อไปนี้ไว้อย่างปลอดภัย

  • รหัสแอปพลิเคชัน (ไคลเอ็นต์)
  • รหัสไดเรกทอรี (ผู้เช่า)


Google, Google Workspace รวมถึงเครื่องหมายและโลโก้ที่เกี่ยวข้องเป็นเครื่องหมายการค้าของ Google LLC ชื่อบริษัทและชื่อผลิตภัณฑ์อื่นๆ ทั้งหมดเป็นเครื่องหมายการค้าของบริษัทที่เกี่ยวข้อง