You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过PowerShell与Microsoft Graph复制Planner任务的受让人等信息

解决Planner任务迁移中受让人、附件、Bucket及备注同步问题

核心问题分析及修复方案

1. 受让人同步失败

原脚本遍历$task.Assignments的方式错误,Planner任务的Assignments是用户ID为键的字典结构,而非数组。同时,创建新任务时assignments的格式必须是键值对(用户ID作为键),而非数组。

修复方式:

  • 遍历$task.Assignments的键(用户ID)
  • 按Graph API要求的格式构建assignments对象,保留原任务的assignedDateTime、orderHint等属性

2. 备注无法同步

Get-MgPlannerPlanTask默认不会返回任务的Details属性(包含备注),必须添加-ExpandProperty Details参数才能获取。

3. 附件同步失败

  • 同样,默认不返回Attachments,需添加-ExpandProperty Attachments
  • Planner不支持在创建任务时直接附加附件,必须先创建任务,再通过New-MgPlannerTaskAttachment单独添加每个附件

4. Bucket信息错误

原脚本错误地取目标计划第一个任务的BucketId,正确逻辑是:匹配源任务Bucket的名称,在目标计划中找到对应Bucket的ID(因为Bucket是计划专属,跨计划ID不同)


修正后的完整脚本

# PowerShell script to copy planner tasks from one plan to another
# Requires Microsoft Graph PowerShell module

# Define your variables
$tenant = "" # Your tenant ID
$clientid = "" # Your registered application client ID
$thumbprint = "" # Thumbprint of your registered application certificate
$sourcePlanId = "" # ID of the source plan
$destinationPlanId = "" # ID of the destination plan

# Connect to Microsoft Graph 
Connect-MgGraph -ClientId $clientid -TenantId $tenant -CertificateThumbprint $thumbprint

# Get source plan buckets (for name matching later)
$sourceBuckets = Get-MgPlannerPlanBucket -PlannerPlanId $sourcePlanId
# Get destination plan buckets
$destinationBuckets = Get-MgPlannerPlanBucket -PlannerPlanId $destinationPlanId

# Get top 3 tasks from source plan, expand Details and Attachments
$sourceTasks = Get-MgPlannerPlanTask -PlannerPlanId $sourcePlanId -Top 3 -ExpandProperty Details,Attachments

$movedTasksCount = 0

foreach ($task in $sourceTasks) {
    # --------------------------
    # 1. 处理受让人
    # --------------------------
    $assignments = @{}
    if ($task.Assignments) {
        Write-Host "Task $($task.Title) has assignees:"
        # 遍历Assignments的键(用户ID)
        foreach ($userId in $task.Assignments.Keys) {
            $assignment = $task.Assignments[$userId]
            Write-Host "Assignee User ID: $userId"
            # 按Graph要求的格式构建赋值对象
            $assignments[$userId] = @{
                assignedDateTime = $assignment.AssignedDateTime
                orderHint        = $assignment.OrderHint
                assignedBy       = $assignment.AssignedBy
            }
        }
    }
    else {
        Write-Host "Task $($task.Title) has no assignees."
    }

    # --------------------------
    # 2. 处理Bucket
    # --------------------------
    $bucketId = $null
    if ($task.BucketId) {
        # 找到源Bucket的名称
        $sourceBucket = $sourceBuckets | Where-Object { $_.Id -eq $task.BucketId }
        if ($sourceBucket) {
            # 在目标计划中匹配同名Bucket
            $destinationBucket = $destinationBuckets | Where-Object { $_.Name -eq $sourceBucket.Name }
            if ($destinationBucket) {
                $bucketId = $destinationBucket.Id
                Write-Host "Task $($task.Title) mapped to destination bucket: $($sourceBucket.Name)"
            }
            else {
                Write-Host "Destination bucket not found for $($sourceBucket.Name) (task: $($task.Title))"
            }
        }
    }
    else {
        Write-Host "Task $($task.Title) does not have a bucket."
    }

    # --------------------------
    # 3. 创建基础任务
    # --------------------------
    $newTaskParams = @{
        planId          = $destinationPlanId
        title           = $task.Title
        labels          = $task.Labels
        percentComplete = $task.PercentComplete
        priority        = $task.Priority
        startDateTime   = $task.StartDateTime
        dueDateTime     = $task.DueDateTime
        notes           = $task.Details.Description
        bucketId        = $bucketId
        assignments     = $assignments
    }

    try {
        $newTask = New-MgPlannerTask -Body $newTaskParams -ErrorAction Stop
        Write-Host "Task created: $($task.Title)"
        $movedTasksCount++

        # --------------------------
        # 4. 添加附件
        # --------------------------
        if ($task.Attachments) {
            Write-Host "Adding attachments to $($task.Title):"
            foreach ($attachment in $task.Attachments.Values) {
                try {
                    $attachmentParams = @{
                        PlannerTaskId = $newTask.Id
                        BodyParameter = @{
                            name        = $attachment.Name
                            contentType = $attachment.ContentType
                            url         = $attachment.Url
                            type        = $attachment.Type
                        }
                    }
                    New-MgPlannerTaskAttachment @attachmentParams -ErrorAction Stop
                    Write-Host "- Added attachment: $($attachment.Name)"
                }
                catch {
                    Write-Host "- Failed to add attachment $($attachment.Name): $_"
                }
            }
        }
        else {
            Write-Host "Task $($task.Title) has no attachments."
        }

        # 可选:删除源任务
        # Remove-MgPlannerTask -PlannerTaskId $task.Id -ErrorAction Stop
        # Write-Host "Source task deleted: $($task.Title)"
    }
    catch {
        Write-Host "Failed to create task $($task.Title): $_"
        continue
    }
}

Write-Host "`nTotal tasks moved: $movedTasksCount"

关键修改说明

  1. 获取任务详情:添加-ExpandProperty Details,Attachments到Get-MgPlannerPlanTask,确保拿到备注和附件数据
  2. 受让人处理:遍历Assignments的键(用户ID),构建符合要求的字典结构赋值对象
  3. Bucket匹配:通过Bucket名称在目标计划中找到对应的Bucket ID,而非随机取任务的Bucket
  4. 附件添加:先创建任务,再逐个添加附件,遵循Planner API的限制

内容的提问来源于stack exchange,提问作者user3408132

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 08:35:09