为 OneDrive 设置 Azure 应用

请按照以下步骤在 Azure 门户中创建 Microsoft Azure 应用。 如果您使用高级数据导入方法将 OneDrive 数据复制到 Google Workspace 账号,则需要 Azure 应用来确保数据导入安全无虞。您可以选择以下两种方法之一:

使用 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 ---
    # Updated Map containing only the requested Graph permissions
    $PermissionMap = @{
        "licenseassignment.read.all"  = "LicenseAssignment.Read.All"     
        "application.read.all"        = "Application.Read.All"
    }
    
    $TenantId = $Context.TenantId
    $GraphAppId = "00000003-0000-0000-c000-000000000000"
    $SpoAppId   = "00000003-0000-0ff1-ce00-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
        
        # 1. Process Microsoft Graph Permissions
        $GraphSP = Get-MgServicePrincipal -Filter "AppId eq '$GraphAppId'" | Select-Object -First 1
        $GraphResourceAccessList = @()
    
        foreach ($key in $PermissionMap.Keys) {
            $RealRoleName = $PermissionMap[$key]
            $Role = $GraphSP.AppRoles | Where-Object { $_.Value -eq $RealRoleName }
    
            if ($Role) {
                $GraphResourceAccessList += @{ 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 (Graph): $RealRoleName" -ForegroundColor Gray
            }
        }
    
        # 2. Process SharePoint Online Permissions
        $SpoSP = Get-MgServicePrincipal -Filter "AppId eq '$SpoAppId'" | Select-Object -First 1
        $SpoResourceAccessList = @()
        $SpoRole = $SpoSP.AppRoles | Where-Object { $_.Value -eq "Sites.FullControl.All" }
    
        if ($SpoRole) {
            $SpoResourceAccessList += @{ id = $SpoRole.Id; type = "Role" }
    
            New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $NewServicePrincipal.Id -BodyParameter @{
                principalId = $NewServicePrincipal.Id
                resourceId  = $SpoSP.Id
                appRoleId   = $SpoRole.Id
            } | Out-Null
            Write-Host " - Granted (SharePoint): Sites.FullControl.All" -ForegroundColor Gray
        }
    
        Update-MgApplication -ApplicationId $Application.Id -RequiredResourceAccess @(
            @{ resourceAppId = $GraphAppId; resourceAccess = $GraphResourceAccessList },
            @{ resourceAppId = $SpoAppId; resourceAccess = $SpoResourceAccessList }
        )
    
        # --- 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. 请记下以下凭据并妥善存储。如果凭据泄露,黑客可能会访问您的所有 OneDrive 数据。
    • 客户端密钥
    • 应用(客户端)ID
    • 目录(租户)ID

方法 2:使用 Windows PowerShell

  1. 在 Windows 中,创建一个新的纯文本文件,并将其命名为 migration_app_creator.ps1
  2. 复制以下代码块,将其粘贴到新文件中,然后点击使用 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 ---
    # Application Permissions mapped to their respective API App IDs
    $ApiConfigurations = @{
        "00000003-0000-0000-c000-000000000000" = @("LicenseAssignment.Read.All", "Application.Read.All") # Microsoft Graph
        "00000003-0000-0ff1-ce00-000000000000" = @("Sites.FullControl.All")                              # SharePoint Online
    }
    
    $TenantId = $Context.TenantId
    
    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
        
        $RequiredResourceAccess = @()
    
        foreach ($ApiAppId in $ApiConfigurations.Keys) {
            $ApiSP = Get-MgServicePrincipal -Filter "AppId eq '$ApiAppId'" | Select-Object -First 1
            $ResourceAccessList = @()
            
            foreach ($RoleName in $ApiConfigurations[$ApiAppId]) {
                $Role = $ApiSP.AppRoles | Where-Object { $_.Value -eq $RoleName }
                
                if ($Role) {
                    $ResourceAccessList += @{ id = $Role.Id; type = "Role" }
                    
                    New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $NewServicePrincipal.Id -BodyParameter @{
                        principalId = $NewServicePrincipal.Id
                        resourceId  = $ApiSP.Id
                        appRoleId   = $Role.Id
                    } | Out-Null
                    Write-Host " - Granted: $RoleName" -ForegroundColor Gray
                }
            }
            
            if ($ResourceAccessList.Count -gt 0) {
                $RequiredResourceAccess += @{
                    resourceAppId  = $ApiAppId
                    resourceAccess = $ResourceAccessList
                }
            }
        }
    
        Update-MgApplication -ApplicationId $Application.Id -RequiredResourceAccess $RequiredResourceAccess
    
        # --- 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"
    
       
  3. 请记下以下凭据并妥善存储。如果凭据泄露,黑客可能会访问您的所有 OneDrive 数据。
    • 客户端密钥
    • 应用(客户端)ID
    • 目录(租户)ID

使用 Microsoft Azure 设置手动连接

Microsoft 的具体步骤可能会因您的 Azure 门户版本和 Microsoft 进行的更新而异。如需了解有关应用注册和授权的最新指南,请参阅 Microsoft 的文档。

第 1 步:注册新应用

  1. 以管理员身份登录 Azure 门户。
  2. 在 Azure 服务中,前往应用注册
  3. 点击新注册,然后为您的应用输入名称(例如“高级导入应用”)。
  4. 对于支持的账号类型,点击仅此组织目录中的账号,以创建单租户应用。
  5. 点击注册

第 2 步:配置 API 权限

请从下列选项中选择一项:

方法 1:手动添加权限

  1. 在侧边的管理部分中,点击 API 权限
  2. 点击添加权限,然后在 Microsoft API 标签页中点击 Sharepoint
  3. 点击应用权限,然后在“网站”下拉菜单中勾选 Sites.FullControl.All 复选框。
  4. 点击添加权限
  5. 返回添加权限,然后选择 Microsoft Graph
  6. 点击“应用权限”,然后授予以下权限:
    • LicenseAssignment.Read.All
    • Application.Read.All
  7. 点击添加权限
  8. 点击为“您的组织”授予管理员同意书,以确保应用有权访问数据。

方法 2:修改应用清单

  1. 打开应用清单。
  2. 前往 “resourceAccess” : [ ],然后选择一个选项:
    • 如果 “resourceAccess” : [ ] 已有值,请添加英文逗号,然后粘贴以下代码块。
    • 如果 “resourceAccess” : [ ] 没有值,请复制并粘贴以下代码块。
         "requiredResourceAccess": [
          {
              "resourceAppId": "00000003-0000-0000-c000-000000000000",
              "resourceAccess": [
                  {
                      "id": "e2f98668-2877-4f38-a2f4-8202e0717aa1",
                      "type": "Role"
                  },
                  {
                      "id": "9a5d68dd-52b0-4cc2-bd40-abcf44ac3a30",
                      "type": "Role"
                  }
              ]
          },
          {
              "resourceAppId": "00000003-0000-0ff1-ce00-000000000000",
              "resourceAccess": [
                  {
                      "id": "678536fe-1083-478a-9c59-b99265e6b0d3",
                      "type": "Role"
                  }
              ]
          }
      ]
         
  3. 点击您的组织授予管理员同意书

第 3 步:生成客户端密钥

  1. 在侧边栏中,依次点击管理下的证书和密钥 然后 新建客户端密钥
  2. 输入说明,选择有效期,然后点击添加
  3. 复制客户端密钥值并妥善存储。该值仅显示一次。

第 4 步:收集应用凭据

重要提示:请妥善存储应用凭据。如果凭据泄露,黑客可能会访问您的所有 OneDrive 数据。

点击概览,并妥善记录以下凭据:

  • 应用(客户端)ID
  • 目录(租户)ID


Google、Google Workspace 以及相关标志和徽标是 Google LLC 的商标。其他所有公司名和产品名是其各自相关公司的商标。