如何通过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"
关键修改说明
- 获取任务详情:添加
-ExpandProperty Details,Attachments到Get-MgPlannerPlanTask,确保拿到备注和附件数据 - 受让人处理:遍历
Assignments的键(用户ID),构建符合要求的字典结构赋值对象 - Bucket匹配:通过Bucket名称在目标计划中找到对应的Bucket ID,而非随机取任务的Bucket
- 附件添加:先创建任务,再逐个添加附件,遵循Planner API的限制
内容的提问来源于stack exchange,提问作者user3408132
相关产品推荐
相关产品推荐

