functions/update-adoclassificationnode.ps1
<# .SYNOPSIS Updates a classification node (Area or Iteration). .DESCRIPTION Uses the Azure DevOps Work Item Tracking REST API (Classification Nodes - Update) to update an existing classification node. Supports: - Renaming nodes by providing a new Name - Updating iteration dates (StartDate/FinishDate) - Setting custom attributes via hashtable .OUTPUTS ADO.TOOLS.WorkItem.ClassificationNode .PARAMETER Organization Azure DevOps organization name (e.g. contoso). .PARAMETER Project Project name or id. .PARAMETER Token Personal Access Token (PAT) with vso.work_write scope. .PARAMETER StructureGroup Areas | Iterations - specifies whether this is an Area or Iteration node. .PARAMETER Path Path of the classification node to update (e.g. 'ParentArea\ChildArea'). Leave empty to update the root node. .PARAMETER Name New name for the classification node (optional). .PARAMETER StartDate New start date for Iteration nodes (ISO 8601 format, e.g. '2024-10-27T00:00:00Z'). .PARAMETER FinishDate New finish date for Iteration nodes (ISO 8601 format, e.g. '2024-10-31T00:00:00Z'). .PARAMETER Attributes Hashtable of attributes to update (alternative to individual date parameters). .PARAMETER ApiVersion API version (default 7.2-preview.2). .EXAMPLE PS> Update-ADOClassificationNode -Organization contoso -Project WebApp -Token $pat -StructureGroup Areas -Path "Frontend Team" -Name "UI Team" Renames the "Frontend Team" area to "UI Team". .EXAMPLE PS> Update-ADOClassificationNode -Organization contoso -Project WebApp -Token $pat -StructureGroup Iterations -Path "Sprint 1" -StartDate "2024-01-01T00:00:00Z" -FinishDate "2024-01-15T00:00:00Z" Updates Sprint 1 iteration with new start and finish dates. .EXAMPLE PS> Update-ADOClassificationNode -Organization contoso -Project WebApp -Token $pat -StructureGroup Iterations -Path "Current Sprint" -Attributes @{ startDate = "2024-02-01T00:00:00Z"; finishDate = "2024-02-14T00:00:00Z" } Updates iteration dates using the Attributes hashtable. .EXAMPLE PS> Update-ADOClassificationNode -Organization contoso -Project WebApp -Token $pat -StructureGroup Areas -Name "New Root Area Name" Renames the root Areas node. .LINK https://learn.microsoft.com/azure/devops .NOTES Author: Oleksandr Nikolaiev (@onikolaiev) #> function Update-ADOClassificationNode { [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")] [CmdletBinding()] [OutputType('ADO.TOOLS.WorkItem.ClassificationNode')] param( [Parameter(Mandatory=$true)] [string]$Organization, [Parameter(Mandatory=$true)] [string]$Project, [Parameter(Mandatory=$true)] [string]$Token, [Parameter(Mandatory=$true)] [ValidateSet('Areas','Iterations')] [string]$StructureGroup, [Parameter()] [string]$Path, [Parameter()] [string]$Name, [Parameter()] [datetime]$StartDate, [Parameter()] [datetime]$FinishDate, [Parameter()] [hashtable]$Attributes, [Parameter()] [string]$ApiVersion = '7.2-preview.2' ) begin { Write-PSFMessage -Level Verbose -Message "Starting update of classification node '$Path' (Group: $StructureGroup) (Org: $Organization / Project: $Project)" Invoke-TimeSignal -Start # Validate that at least one update parameter is provided if (-not $Name -and -not $StartDate -and -not $FinishDate -and -not $Attributes) { Stop-PSFFunction -Message "At least one update parameter must be provided: Name, StartDate, FinishDate, or Attributes" -Target 'Update-ADOClassificationNode' return } } process { if (Test-PSFFunctionInterrupt) { return } try { # Build API URI with encoded path $basePath = "$Project/_apis/wit/classificationnodes/$StructureGroup" if ($Path) { # URL encode the path segments $pathSegments = $Path.Split('\', [StringSplitOptions]::RemoveEmptyEntries) $encodedSegments = $pathSegments | ForEach-Object { [System.Uri]::EscapeDataString($_) } $basePath += '/' + ($encodedSegments -join '/') } Write-PSFMessage -Level Verbose -Message "API path: $basePath" # Prepare request body $body = @{} # Add name if provided if ($Name) { $body['name'] = $Name Write-PSFMessage -Level Verbose -Message "Updating name to: $Name" } # Handle attributes (dates for iterations) $nodeAttributes = @{} if ($StartDate) { $nodeAttributes['startDate'] = $StartDate.ToString('yyyy-MM-ddTHH:mm:ssZ') } if ($FinishDate) { $nodeAttributes['finishDate'] = $FinishDate.ToString('yyyy-MM-ddTHH:mm:ssZ') } # Merge with provided attributes hashtable if ($Attributes) { foreach ($key in $Attributes.Keys) { $nodeAttributes[$key] = $Attributes[$key] } } if ($nodeAttributes.Count -gt 0) { $body['attributes'] = $nodeAttributes Write-PSFMessage -Level Verbose -Message "Updating $($nodeAttributes.Count) attribute(s)" } # Validate we have something to update if ($body.Count -eq 0) { throw "No valid update parameters provided" } # Convert to JSON $jsonBody = $body | ConvertTo-Json -Depth 10 -Compress Write-PSFMessage -Level Verbose -Message "Request body: $jsonBody" # Make API call $response = Invoke-ADOApiRequest -Organization $Organization ` -Token $Token ` -ApiUri $basePath ` -Method 'PATCH' ` -Body $jsonBody ` -Headers @{'Content-Type' = 'application/json'} ` -ApiVersion $ApiVersion Write-PSFMessage -Level Verbose -Message "Successfully updated classification node (ID: $($response.Results.id))" return $response.Results | Select-PSFObject * -TypeName 'ADO.TOOLS.WorkItem.ClassificationNode' } catch { Write-PSFMessage -Level Error -Message "Failed to update classification node '$Path': $($_.Exception.Message)" -Exception $PSItem.Exception Stop-PSFFunction -Message "Stopping because of errors" -Target $PSCmdlet.MyInvocation.MyCommand.Name -ErrorRecord $_ } } end { Write-PSFMessage -Level Verbose -Message "Completed classification node update operation" Invoke-TimeSignal -End } } |