ตั้งค่าแอปพลิเคชัน Azure สำหรับการนำเข้าข้อมูลขั้นสูง

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

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

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

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

  1. ลงชื่อเข้าใช้พอร์ทัล Azure ในฐานะผู้ดูแลระบบ
  2. คลิก Cloud Shellจากนั้นPowershell
  3. เมื่อได้รับข้อความแจ้ง ให้สร้างบัญชีพื้นที่เก็บข้อมูลและยอมรับการตั้งค่าเริ่มต้น
  4. หากต้องการสร้างแอปพลิเคชัน ให้ป้อนคำสั่งต่อไปนี้ แล้วคลิก Enter:

    Install-Module Microsoft.Graph -Scope CurrentUser

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

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

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

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

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

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

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

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

    1. คลิก API permissions ในส่วน Manage ทางด้านข้าง
    2. คลิก Add a permissionจากนั้นMicrosoft APIsจากนั้นMicrosoft Graph.
    3. สำหรับสิทธิ์ของแอปพลิเคชัน ให้เลือกรายการต่อไปนี้
      • Calendars.Read
      • Contacts.Read
      • Directory.Read.All
      • Group-Conversation.Read.All
      • Mail.Read
      • MailboxFolder.Read.All
      • MailboxItem.Export.All
      • MailboxItem.Read.All
      • Tasks.Read.All
      • User.Read.All
    4. คลิก Grant admin consent for your organization

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

    1. เปิดไฟล์ Manifest ของแอปพลิเคชัน
    2. ไปที่ “resourceAccess” : [ ]แล้วเลือกตัวเลือกต่อไปนี้
      • หาก “resourceAccess” : [ ] มีค่าอยู่แล้ว ให้ใส่คอมมาแล้ววางโค้ดบล็อกต่อไปนี้
      • หาก “resourceAccess” : [ ] ไม่มีค่า ให้คัดลอกและวางโค้ดบล็อกต่อไปนี้

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

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

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

      { "id": "4f0a8235-6f6f-4ec7-9500-34b452a4a0c3", "type": "Role" },

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

      { "id": "99280d24-a782-4793-93cc-0888549957f6", "type": "Role" },

      { "id": "937550e9-33a3-494b-88ae-d9cd394b1fbb", "type": "Role" },

      { "id": "7d9f353d-a7bd-4fbb-822a-26d5dd39a3ce", "type": "Role" },

      { "id": "f10e1f91-74ed-437f-a6fd-d6ae88e26c1f", "type": "Role" },

      { "id": "df021288-bdef-4463-88db-98f22de89214", "type": "Role" }

    3. คลิก Grant admin consent for your organization

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

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

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

    สำคัญ: เก็บข้อมูลเข้าสู่ระบบของแอปพลิเคชันไว้ในที่ปลอดภัย หากข้อมูลเข้าสู่ระบบรั่วไหล แฮ็กเกอร์อาจเข้าถึงข้อมูล Exchange ทั้งหมดของคุณได้

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

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


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