Public/DataImportTool/Repair-ProcessConfiguration.ps1

function Repair-ProcessConfiguration {
    <#
    .SYNOPSIS
    Exports a project's ProjectProcessConfiguration, repairs it to Data Import Tool
    requirements (TypeFields, backlog categories/names/states/columns, feedback work
    items), and imports it back.
 
    .DESCRIPTION
    Wraps the full export -> edit -> import sequence that otherwise takes ~40 runbook
    lines per project. The state mappings default to an Agile-derived set; they MUST match
    the actual workflow states of the project's work item types or witadmin will reject
    the import - check with Get-WitWorkItemTypeState first and override -RequirementStates /
    -TaskStates where they differ.
 
    Run Install-FeedbackWorkItemTypes for the project first: the feedback categories
    referenced here must already exist.
 
    Use -SkipImport to stop after editing the local XML so it can be reviewed before
    pushing it back with Import-WitProcessConfigurationFixFile.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)] [string]$Collection,
        [Parameter(Mandatory)] [string]$Project,
        [Parameter(Mandatory)] [string]$Path,
        [hashtable[]]$RequirementStates = @(
            @{ Type = 'Proposed'; Value = 'Proposed' }
            @{ Type = 'InProgress'; Value = 'Resolved' }
            @{ Type = 'InProgress'; Value = 'Active' }
            @{ Type = 'InProgress'; Value = 'QAReview' }
            @{ Type = 'Complete'; Value = 'Closed' }
            @{ Type = 'Complete'; Value = 'Inactive' }
        ),
        [hashtable[]]$TaskStates = @(
            @{ Type = 'Proposed'; Value = 'Pending' }
            @{ Type = 'InProgress'; Value = 'Active' }
            @{ Type = 'Complete'; Value = 'Closed' }
            @{ Type = 'Complete'; Value = 'Cancelled' }
        ),
        [string]$RequirementSingularName = 'User Story',
        [string]$RequirementPluralName = 'User Stories',
        [string]$EffortReferenceName = 'Microsoft.VSTS.Scheduling.StoryPoints',
        [switch]$SkipImport,
        [string]$WitAdminPath
    )

    Write-FixStep "Repairing process configuration for '$Project' via '$Path'"
    Export-WitProcessConfigurationFixFile -Collection $Collection -Project $Project -Path $Path -WitAdminPath $WitAdminPath

    # TypeFields (refnames taken from the OOB Agile template)
    Add-ProcessConfigurationElement -Path $Path -ParentXPath '/ProjectProcessConfiguration' -ElementName 'TypeFields'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'Team' -ReferenceName 'System.AreaPath'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'RemainingWork' -ReferenceName 'Microsoft.VSTS.Scheduling.RemainingWork' -Format '{0} h'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'Order' -ReferenceName 'Microsoft.VSTS.Common.StackRank'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'Effort' -ReferenceName $EffortReferenceName
    Add-ProcessConfigurationTypeField -Path $Path -Type 'Activity' -ReferenceName 'Microsoft.VSTS.Common.Activity'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'ApplicationStartInformation' -ReferenceName 'Microsoft.VSTS.Feedback.ApplicationStartInformation'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'ApplicationLaunchInstructions' -ReferenceName 'Microsoft.VSTS.Feedback.ApplicationLaunchInstructions'
    Add-ProcessConfigurationTypeField -Path $Path -Type 'ApplicationType' -ReferenceName 'Microsoft.VSTS.Feedback.ApplicationType' -Values @(
        @{ Type = 'ClientApp'; Value = 'Client application' }
        @{ Type = 'RemoteMachine'; Value = 'Remote machine' }
        @{ Type = 'WebApp'; Value = 'Web application' }
    )

    # RequirementBacklog (category, names, states, columns, add panel)
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/RequirementBacklog' -AttributeName 'category' -Value 'Microsoft.RequirementCategory'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/RequirementBacklog' -AttributeName 'pluralName' -Value $RequirementPluralName
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/RequirementBacklog' -AttributeName 'singularName' -Value $RequirementSingularName
    Set-ProcessConfigurationStates -Path $Path -BacklogElement 'RequirementBacklog' -States $RequirementStates
    Set-ProcessConfigurationColumns -Path $Path -BacklogElement 'RequirementBacklog' -Columns @(
        @{ ReferenceName = 'System.WorkItemType'; Width = 100 }
        @{ ReferenceName = 'System.Title'; Width = 400 }
        @{ ReferenceName = 'System.State'; Width = 100 }
        @{ ReferenceName = $EffortReferenceName; Width = 50 }
    )
    Set-ProcessConfigurationAddPanel -Path $Path -BacklogElement 'RequirementBacklog' -Fields @('System.Title')

    # TaskBacklog (category, names, states, columns, add panel)
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/TaskBacklog' -AttributeName 'category' -Value 'Microsoft.TaskCategory'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/TaskBacklog' -AttributeName 'pluralName' -Value 'Tasks'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/TaskBacklog' -AttributeName 'singularName' -Value 'Task'
    Set-ProcessConfigurationStates -Path $Path -BacklogElement 'TaskBacklog' -States $TaskStates
    Set-ProcessConfigurationColumns -Path $Path -BacklogElement 'TaskBacklog' -Columns @(
        @{ ReferenceName = 'System.WorkItemType'; Width = 100 }
        @{ ReferenceName = 'System.Title'; Width = 400 }
        @{ ReferenceName = 'System.State'; Width = 100 }
        @{ ReferenceName = 'Microsoft.VSTS.Scheduling.RemainingWork'; Width = 50 }
    )
    Set-ProcessConfigurationAddPanel -Path $Path -BacklogElement 'TaskBacklog' -Fields @('System.Title')

    # Feedback work items (states taken from the OOB Agile template)
    Add-ProcessConfigurationElement -Path $Path -ParentXPath '/ProjectProcessConfiguration' -ElementName 'FeedbackRequestWorkItems'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/FeedbackRequestWorkItems' -AttributeName 'category' -Value 'Microsoft.FeedbackRequestCategory'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/FeedbackRequestWorkItems' -AttributeName 'pluralName' -Value 'Feedback Requests'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/FeedbackRequestWorkItems' -AttributeName 'singularName' -Value 'Feedback Request'
    Set-ProcessConfigurationStates -Path $Path -BacklogElement 'FeedbackRequestWorkItems' -States @(
        @{ Type = 'InProgress'; Value = 'Active' }
        @{ Type = 'Complete'; Value = 'Closed' }
    )
    Add-ProcessConfigurationElement -Path $Path -ParentXPath '/ProjectProcessConfiguration' -ElementName 'FeedbackResponseWorkItems'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/FeedbackResponseWorkItems' -AttributeName 'category' -Value 'Microsoft.FeedbackResponseCategory'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/FeedbackResponseWorkItems' -AttributeName 'pluralName' -Value 'Feedback Responses'
    Set-ProcessConfigurationAttribute -Path $Path -XPath '/ProjectProcessConfiguration/FeedbackResponseWorkItems' -AttributeName 'singularName' -Value 'Feedback Response'
    Set-ProcessConfigurationStates -Path $Path -BacklogElement 'FeedbackResponseWorkItems' -States @(
        @{ Type = 'InProgress'; Value = 'Active' }
        @{ Type = 'Complete'; Value = 'Closed' }
    )

    if ($SkipImport) {
        Write-FixStep "SkipImport set - review '$Path' then run Import-WitProcessConfigurationFixFile to apply it"
        return
    }
    Import-WitProcessConfigurationFixFile -Collection $Collection -Project $Project -Path $Path -WitAdminPath $WitAdminPath

    # Verify the server retained the repair rather than silently discarding
    # elements: re-export and check the pieces this function is responsible for.
    $verifyFile = Join-Path ([System.IO.Path]::GetTempPath()) "$([guid]::NewGuid()).ProcessConfig.xml"
    try {
        Export-WitProcessConfigurationFixFile -Collection $Collection -Project $Project -Path $verifyFile -WitAdminPath $WitAdminPath
        $verify = [xml](Get-Content -LiteralPath $verifyFile -Raw)
        $missing = @(
            if (-not $verify.SelectSingleNode('/ProjectProcessConfiguration/TypeFields/TypeField')) { 'TypeFields' }
            if (-not $verify.SelectSingleNode("/ProjectProcessConfiguration/RequirementBacklog[@category='Microsoft.RequirementCategory']")) { 'RequirementBacklog@category' }
            if (-not $verify.SelectSingleNode("/ProjectProcessConfiguration/TaskBacklog[@category='Microsoft.TaskCategory']")) { 'TaskBacklog@category' }
            if (-not $verify.SelectSingleNode('/ProjectProcessConfiguration/FeedbackRequestWorkItems/States/State')) { 'FeedbackRequestWorkItems' }
            if (-not $verify.SelectSingleNode('/ProjectProcessConfiguration/FeedbackResponseWorkItems/States/State')) { 'FeedbackResponseWorkItems' }
        )
        if ($missing) {
            throw "Verification failed: after import, '$Project' is still missing: $($missing -join ', ')."
        }
        Write-FixStep " verified: re-export retains TypeFields, backlog categories and feedback elements"
    }
    finally {
        Remove-Item -LiteralPath $verifyFile -Force -ErrorAction SilentlyContinue
    }
}