הגדרת אפליקציית Azure להעברה מתקדמת

כדי ליצור אפליקציית Microsoft Azure ב-Azure Portal, פועלים לפי השלבים הבאים. כדי להבטיח מיגרציה מאובטחת של נתונים מ-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 (הפעלה באמצעות 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 כדי להגדיר חיבור ידני

    השלבים הספציפיים של מיקרוסופט עשויים להשתנות בהתאם לגרסה של פורטל Azure ולעדכונים שמיקרוסופט מבצעת. לקבלת ההנחיות העדכניות בנושא רישום והרשאה של אפליקציות, אפשר לעיין במסמכי התיעוד של מיקרוסופט.

    שלב 1: רישום אפליקציה חדשה

    מטעמי אבטחה, מומלץ לרשום את האפליקציה החדשה כדייר יחיד.

    1. אדמינים צריכים להיכנס לפורטל Azure.
    2. ב-Azure Active Directory (Azure AD), עוברים אל App registrations.
    3. לוחצים על New Registration (רישום חדש) ומזינים שם לאפליקציה (לדוגמה, Advanced migration app).
    4. בקטע סוגי חשבונות נתמכים, לוחצים על חשבונות רק בספרייה הארגונית הזו כדי ליצור אפליקציה עם דייר יחיד.
    5. לוחצים על הרשמה.

    שלב 2: הגדרת הרשאות API

    בוחרים אחת מהאפשרויות האלה:

    אפשרות 1: הוספת הרשאות באופן ידני

    1. בצד, בקטע ניהול, לוחצים על הרשאות API.
    2. לוחצים על Add a permission (הוספת הרשאה)ואזMicrosoft APIs (ממשקי API של מיקרוסופט)ואזMicrosoft Graph (מיקרוסופט גרף).
    3. בקטע הרשאות לאפליקציה, בוחרים:
      • calendars.read
      • mail.read
      • contacts.read
      • Directory.read.all
    4. לוחצים על Grant admin consent for your organization (מתן הסכמת אדמין לארגון שלך).

    אפשרות 2: עריכת המניפסט של האפליקציה

    1. פותחים את קובץ המניפסט של האפליקציה.
    2. עוברים אל “resourceAccess” : [ ] ובוחרים באחת מהאפשרויות:
      • אם כבר יש ערך ל-“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. בצד, בקטע Manage (ניהול), לוחצים על Certificates & secrets (אישורים וסודות)ואזNew client secret (סוד לקוח חדש).
    2. מזינים תיאור, בוחרים תקופת תפוגה ולוחצים על הוספה.
    3. מעתיקים את ערך סוד הלקוח ומאחסנים אותו באופן מאובטח. הערך מוצג רק פעם אחת.

    שלב 4: אוספים את פרטי הכניסה של האפליקציה

    חשוב: צריך לאחסן את פרטי הכניסה של האפליקציה בצורה מאובטחת. אם פרטי הכניסה ידלפו, האקרים יוכלו לגשת לכל הנתונים שלכם ב-Exchange.

    לוחצים על Overview ורושמים בצורה מאובטחת את פרטי הכניסה הבאים:

    • מזהה האפליקציה (אפליקציית הלקוח)
    • מזהה הספרייה (הדייר)


    Google‏, Google Workspace וסימנים וסמלי לוגו קשורים הם סימנים מסחריים של Google LLC. כל שמות החברות והמוצרים האחרים הם סימנים מסחריים של החברות שאליהן הם משויכים.