I'm looping through an Azure DevOps query script to essentially create copies of work items into a new iteration. The problem I'm having is with the final Invoke-RestMethod call at the end of the script. It returns this:
Invoke-RestMethod : {
"$id":"1",
"innerException":null,"message":"Value cannot be null.",
"typeName":"Microsoft.VisualStudio.Services.Common.VssPropertyValidationException,
Microsoft.VisualStudio.Services.Common",
"typeKey":"VssPropertyValidationException",
"errorCode":0,
"eventId":3000
}
Any ideas where I went wrong?
$organization = "mycompany"
$project = "MyProject"
$pat = "myPAT"
$headers = @{
Authorization = "Basic " +
[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$pat"))
}
$newIterationPath = "IT Main\Production Support\2025\2025.4.3"
# Encode PAT for Authorization header
$base64AuthInfo = [Convert]::ToBase64String(
[Text.Encoding]::ASCII.GetBytes(":$pat")
)
### 1. Run WIQL query to get work item IDs
$wiqlUrl = "https://dev.azure.com/$organization/$project" +
"/_apis/wit/wiql/798dee4f-b063-4f4f-a710-415c590a4dcc?" +
"api-version=7.0"
$response = Invoke-RestMethod -Uri $wiqlUrl -Method Get -Headers $headers
$workItemIds = $response.workItems.id
### 2. Get details of each work item
foreach ($id in $workItemIds) {
$workItemUrl = "https://dev.azure.com/$organization/$project" +
"/_apis/wit/workitems/$($id)?api-version=7.0"
$workItem = Invoke-RestMethod -Uri $workItemUrl -Headers $headers
# Prepare fields for new work item
$fields = @(
@{
"op" = "add"
"path" = "/fields/System.Title"
"value" = $workItem.fields.'System.Title'
},
@{
"op" = "add"
"path" = "/fields/System.Description"
"value" = $workItem.fields.'System.Description'
},
@{
"op" = "add"
"path" = "/fields/System.AreaPath"
"value" = $workItem.fields.'System.AreaPath'
},
@{
"op" = "add"
"path" = "/fields/System.IterationPath"
"value" = $newIterationPath
},
@{
"op" = "add"
"path" = "/fields/System.AssignedTo"
"value" = $workItem.fields.'System.AssignedTo'
}
)
$body = (ConvertTo-JSON $fields)
### 3. Create new work item in target iteration
$createUrl = "https://dev.azure.com/$organization/$project/_apis/wit/workitems/$" +
$workItem.fields.'System.WorkItemType' + "?api-version=7.0"
$newWorkItem = Invoke-RestMethod `
-Uri $createUrl `
-Method POST `
-Headers $headers `
-ContentType "application/json-patch+json" `
-Body $body
Write-Host "Created new work item: $($newWorkItem.id)"
}
Below is a sample of the PowerShell script that I run on my side to create a new work item and copy some field values from an existing work item with the same work item type. It can work as expected without any error. You can reference to it when correcting your PowerShell script.
The PowerShell script:
# copyWitToNewWit.ps1
$pat = "xxxx"
$organization = "xxxx"
$project = "ProjDemo"
$witId = 269
$newIterationPath = "ProjDemo\\Iteration-2024\\Iteration-M02"
$base64Token = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "", $pat)))
$headers = @{
Authorization = "Basic $base64Token"
"Content-Type" = "application/json-patch+json"
}
$getWitUri = "https://dev.azure.com/${organization}/${project}/_apis/wit/workitems/${witId}?api-version=7.1"
$getWitResponse = Invoke-RestMethod -Method GET -Uri $getWitUri -Headers $headers
$createWitUri = "https://dev.azure.com/${organization}/${project}/_apis/wit/workitems/`$" + $getWitResponse.fields.'System.WorkItemType' + "?api-version=7.1"
$createWitBody = @(
@{
op = "add"
path = "/fields/System.Title"
value = $getWitResponse.fields.'System.Title'
}
@{
op = "add"
path = "/fields/System.Description"
value = $getWitResponse.fields.'System.Description'
}
@{
op = "add"
path = "/fields/System.AreaPath"
value = $getWitResponse.fields.'System.AreaPath'
}
@{
op = "add"
path = "/fields/System.IterationPath"
value = $newIterationPath
}
@{
op = "add"
path = "/fields/System.AssignedTo"
value = $getWitResponse.fields.'System.AssignedTo'
}
) | ConvertTo-Json -Depth 10
$createWitResponse = Invoke-RestMethod -Method POST -Uri $createWitUri -Headers $headers -Body $createWitBody
Write-Host ("Created new work item: " + $createWitResponse.id + ", and copied some field values from existing work item: $witId.")
The result of executing this PowerShell script: