WorkItem/WorkItem.psm1

Function _FixAreaIterationValues([hashtable] $Fields, $ProjectName)
{
    if ($Fields.ContainsKey('System.AreaPath') -and ($Fields['System.AreaPath'] -notmatch "'\\?$ProjectName\\.+'"))
    {
        $Fields['System.AreaPath'] = ("$ProjectName\$($Fields['System.AreaPath'])" -replace '\\', '\')
    }

    if ($Fields.ContainsKey('System.IterationPath') -and ($Fields['System.IterationPath'] -notmatch "'\\?$ProjectName\\.+'"))
    {
        $Fields['System.IterationPath'] = ("$ProjectName\$($Fields['System.IterationPath'])" -replace '\\', '\')
    }
    
    return $Fields
}
<#
 
.SYNOPSIS
    Gets the links of a work item.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
#>

Function Add-TfsWorkItemLink
{
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [Alias("From")]
        [ValidateNotNull()]
        [object]
        $SourceWorkItem,

        [Parameter(Position=1, Mandatory=$true)]
        [Alias("To")]
        [ValidateNotNull()]
        [object]
        $TargetWorkItem,

        [Parameter(Position=2, Mandatory=$true)]
        [Alias("LinkType")]
        [Alias("Type")]
        [object]
        $EndLinkType,

        [Parameter()]
        [string]
        $Comment,

        [switch]
        $SkipSave,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $sourceWi = Get-TfsWorkItem -WorkItem $SourceWorkItem -Collection $Collection -Project $Project
        $targetWi = Get-TfsWorkItem -WorkItem $TargetWorkItem -Collection $Collection -Project $Project

        
        if ($EndLinkType -isnot [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkTypeEnd])
        {
            try
            {
                $EndLinkType = $sourceWi.Store.WorkItemLinkTypes.LinkTypeEnds[$EndLinkType]
            }
            catch
            {
                throw "Error retrieving work item link type $EndLinkType`: $_"
            }
        }

        $link = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLink' -ArgumentList $EndLinkType, $targetWi.Id
        $link.Comment = $Comment

        $i = $sourceWi.WorkItemLinks.Add($link)

        if (-not $SkipSave)
        {
            $sourceWi.Save()
        }

        return $sourceWi.WorkItemLinks[$i]        
    }
}
<#
 
.SYNOPSIS
    Creates a copy of a work item, optionally changing its type
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
#>

Function Copy-TfsWorkItem
{
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object] 
        $Type,

        [Parameter()]
        [object] 
        $Project,

        [Parameter()]
        [switch] 
        $IncludeAttachments,

        [Parameter()]
        [switch] 
        $IncludeLinks,

        [Parameter()]
        [switch] 
        $SkipSave,

        [Parameter()]
        [ValidateSet('None', 'Original', 'Copy')]
        [string]
        $Passthru = 'None',

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
        $store = $wi.Store

        if($Type)
        {
            if ($Project)
            {
                $tp = $Project
            }
            else
            {
                $tp = $wi.Project
            }
            $witd = Get-TfsWorkItemType -Type $Type -Project $tp -Collection $wi.Store.TeamProjectCollection
        }
        else
        {
            $witd = $wi.Type
        }

        $flags = [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::None

        if ($IncludeAttachments)
        {
            $flags = $flags -bor [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::CopyFiles
        }

        if ($IncludeLinks)
        {
            $flags = $flags -bor [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemCopyFlags]::CopyLinks
        }

        $copy = $wi.Copy($witd, $flags)

        if(-not $SkipSave)
        {
            $copy.Save()
        }

        if ($Passthru -eq 'Original')
        {
            return $wi
        }
        
        if($Passthru -eq 'Copy')
        {
            return $copy
        }
    }
}
<#
 
.SYNOPSIS
    Exports a work item type definition from a team project to XML.
 
.PARAMETER Name
    Uses this parameter to filter for an specific Work Item Type.
    If suppress, cmdlet will return all Work Item Types on XML format.
 
.PARAMETER IncludeGlobalLists
     Exports the definitions of referenced global lists. If not specified, global list definitions are omitted.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
#>

Function Export-TfsWorkItemType
{
    [CmdletBinding()]
    [OutputType([Xml])]
    Param
    (
        [Parameter()]
        [SupportsWildcards()]
        [string] 
        $Name = "*",

        [Parameter()]
        [switch]
        $IncludeGlobalLists,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $types = Get-TfsWorkItemType -Name $Name -Project $Project -Collection $Collection

        foreach($type in $types)
        {
            $type.Export($IncludeGlobalLists)
        }
    }
}
<#
 
.SYNOPSIS
    Gets the contents of one or more work items.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
#>

Function Get-TfsWorkItem
{
    [CmdletBinding(DefaultParameterSetName="Query by text")]
    [OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by revision")]
        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by date")]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter(ParameterSetName="Query by revision")]
        [Alias("rev")]
        [int]
        $Revision,

        [Parameter(Mandatory=$true, ParameterSetName="Query by date")]
        [datetime]
        $AsOf,

        [Parameter(Mandatory=$true, ParameterSetName="Query by WIQL")]
        [Alias('WIQL')]
        [Alias('QueryText')]
        [Alias('SavedQuery')]
        [Alias('QueryPath')]
        [string]
        $Query,

        [Parameter(Mandatory=$true, ParameterSetName="Query by filter")]
        [string]
        $Filter,

        [Parameter(Position=0, Mandatory=$true, ParameterSetName="Query by text")]
        [string]
        $Text,

        [Parameter()]
        [hashtable]
        $Macros,

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($Project)
        {
            $tp = Get-TfsTeamProject -Project $Project -Collection $Collection
            $tpc = $tp.Store.TeamProjectCollection
            $store = $tp.Store
        }
        else
        {
            $tpc = Get-TfsTeamProjectCollection -Collection $Collection
            $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
        }

        if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
        {
            if ((-Not $Revision) -and (-Not $AsOf))
            {
                return $WorkItem
            }
        }

        switch($PSCmdlet.ParameterSetName)
        {
            "Query by revision" {
                return _GetWorkItemByRevision $WorkItem $Revision $store
            }

            "Query by date" {
                return _GetWorkItemByDate $WorkItem $AsOf $store
            }

            "Query by text" {
                $localMacros = @{TfsQueryText=$Text}
                $Wiql = "SELECT * FROM WorkItems WHERE [System.Title] CONTAINS @TfsQueryText OR [System.Description] CONTAINS @TfsQueryText"
                return _GetWorkItemByWiql $Wiql $localMacros $tp $store 
            }

            "Query by filter" {
                $Wiql = "SELECT * FROM WorkItems WHERE $Filter"
                return _GetWorkItemByWiql $Wiql $Macros $tp $store 
            }

            "Query by WIQL" {
                Write-Verbose "Get-TfsWorkItem: Running query by WIQL. Query: $Query"
                return _GetWorkItemByWiql $Query $Macros $tp $store 
            }

            "Query by saved query" {
                return _GetWorkItemBySavedQuery $StoredQueryPath $Macros $tp $store 
            }
        }
    }
}



Function _GetWorkItemByRevision($WorkItem, $Revision, $store)
{
    if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
    {
        $ids = @($WorkItem.Id)
    }
    elseif ($WorkItem -is [int])
    {
        $ids = @($WorkItem)
    }
    elseif ($WorkItem -is [int[]])
    {
        $ids = $WorkItem
    }
    else
    {
        throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
    }

    if ($Revision -is [int] -and $Revision -gt 0)
    {
        foreach($id in $ids)
        {
            $store.GetWorkItem($id, $Revision)
        }
    }
    elseif ($Revision -is [int[]])
    {
        if ($ids.Count -ne $Revision.Count)
        {
            throw "When supplying a list of IDs and Revisions, both must have the same number of elements"
        }
        for($i = 0; $i -le $ids.Count-1; $i++)
        {
            $store.GetWorkItem($ids[$i], $Revision[$i])
        }
    }
    else
    {
        foreach($id in $ids)
        {
            $store.GetWorkItem($id)
        }
    }
}

Function _GetWorkItemByDate($WorkItem, $AsOf, $store)
{
    if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
    {
        $ids = @($WorkItem.Id)
    }
    elseif ($WorkItem -is [int])
    {
        $ids = @($WorkItem)
    }
    elseif ($WorkItem -is [int[]])
    {
        $ids = $WorkItem
    }
    else
    {
        throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
    }

    if ($AsOf -is [datetime[]])
    {
        if ($ids.Count -ne $AsOf.Count)
        {
            throw "When supplying a list of IDs and Changed Dates (AsOf), both must have the same number of elements"
        }
        for($i = 0; $i -le $ids.Count-1; $i++)
        {
            $store.GetWorkItem($ids[$i], $AsOf[$i])
        }
    }
    else
    {
        foreach($id in $ids)
        {
            $store.GetWorkItem($id, $AsOf)
        }
    }
}

Function _GetWorkItemByWiql($QueryText, $Macros, $Project, $store)
{
    if ($QueryText -notlike 'select*')
    {
        $q = Get-TfsWorkItemQuery -Query $QueryText -Project $Project

        if (-not $q)
        {
            throw "Work item query '$QueryText' is invalid or non-existent."
        }

        if ($q.Count -gt 1)
        {
            throw "Ambiguous query name '$QueryText'. $($q.Count) queries were found matching the specified name/pattern:`n`n - " + ($q -join "`n - ")
        }

        $QueryText = $q.QueryText
    }

    if (-not $Macros -and (($QueryText -match "@project") -or ($QueryText -match "@me")))
    {
        $Macros = @{}
    }

    if ($QueryText -match "@project")
    {
        if (-not $Project)
        {
            $Project = Get-TfsTeamProject -Current
        }

        if (-not $Macros.ContainsKey("Project"))
        {
            $Macros["Project"] = $Project.Name
        }
    }

    if ($QueryText -match "@me")
    {
        $user = $null
        $store.TeamProjectCollection.GetAuthenticatedIdentity([ref] $user)
        $Macros["Me"] = $user.DisplayName
    }

    Write-Verbose "Get-TfsWorkItem: Running query $QueryText"

    $wis = $store.Query($QueryText, $Macros)

    foreach($wi in $wis)
    {
        $wi
    }
}
<#
 
.SYNOPSIS
    Gets the history of changes of a work item.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.EXAMPLE
    Get-TfsWorkItem -Filter '[System.WorkItemType] = "Task"' | % { Write-Output "WI $($_.Id): $($_.Title)"; Get-TfsWorkItemHistory -WorkItem $_ }
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
    System.Int32
#>

Function Get-TfsWorkItemHistory
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection
        $latestRev = $wi.Revisions.Count - 1

        0..$latestRev | % {
            $rev = $wi.Revisions[$_]

            [PSCustomObject] @{
                Revision = $_ + 1;
                ChangedDate = $rev.Fields['System.ChangedDate'].Value
                ChangedBy = $rev.Fields['System.ChangedBy'].Value
                Changes = _GetChangedFields $wi $_
            }
        }
    }
}

Function _GetChangedFields([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem] $wi, [int] $rev)
{
    $result = @{}

    $wi.Revisions[$rev].Fields | ? IsChangedInRevision -eq $true | % {
        $result[$_.ReferenceName] =  [PSCustomObject] @{
            NewValue = $_.Value;
            OriginalValue = $_.OriginalValue
        }
    }

    return $result
}
<#
 
.SYNOPSIS
    Gets the links of a work item.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
#>

Function Get-TfsWorkItemLink
{
    [OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.Link])]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $wi = Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection

        if ($wi)
        {
            return $wi.Links
        }
    }
}
<#
 
.SYNOPSIS
    Gets the work item link end types of a team project collection.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.Client.TfsTeamProjectCollection
    System.String
#>

Function Get-TfsWorkItemLinkEndType
{
    [OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemLinkTypeEnd])]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [object]
        $Collection
    )

    Process
    {
        $tpc = Get-TfsTeamProjectCollection -Collection $Collection

        return $tpc.WorkItemStore.WorkItemLinkTypes.LinkTypeEnds
    }
}
<#
 
.SYNOPSIS
    Gets one or more Work Item Type definitions from a team project.
 
.PARAMETER Name
    Uses this parameter to filter for an specific Work Item Type.
    If suppress, cmdlet will show all Work Item Types.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.EXAMPLE
    Get-TfsWorkItemType -Name "Task" -Project "My Team Project"
    Get informations about Work Item Type "Task" of a team project name "My Team Project"
 
.EXAMPLE
    Get-TfsWorkItemType -Project "My Team Project"
    Get all Work Item Types of a team project name "My Team Project"
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.Project
    System.String
#>

Function Get-TfsWorkItemType
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType])]
    Param
    (
        [Parameter(Position=0)]
        [SupportsWildcards()]
        [Alias("Name")]
        [object] 
        $Type = "*",

        [Parameter(ValueFromPipeline=$true)]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($Type -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType])
        {
            return $Type
        }

        $tp = Get-TfsTeamProject -Project $Project -Collection $Collection

        return $tp.WorkItemTypes | ? Name -Like $Type
    }
}
<#
 
.SYNOPSIS
    Imports a work item type definition to a team project from XML.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    System.Xml.XmlDocument
#>

Function Import-TfsWorkItemType
{
    [CmdletBinding()]
    Param
    (
        [Parameter(Position=0, ValueFromPipeline=$true)]
        [xml] 
        $Xml,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $tp = Get-TfsTeamProject $Project $Collection
        $tp.WorkItemTypes.Import($Xml.OuterXml)
    }
}
<#
 
.SYNOPSIS
    Creates a new work item in a team project.
 
.PARAMETER Type
    Represents the name of the work item type to create.
 
.PARAMETER Title
    Specifies a Title field of new work item type that will be created.
 
.PARAMETER Fields
    Specifies the fields that are changed and the new values to give to them.
    FieldN The name of a field to update.
    ValueN The value to set on the fieldN.
    [field1=value1[;field2=value2;...]
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.EXAMPLE
    New-TfsWorkItem -Type Task -Title "Task 1" -Project "MyTeamProject"
    This example creates a new Work Item on Team Project "MyTeamProject".
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType
    System.String
#>

Function New-TfsWorkItem
{
    [CmdletBinding()]
    [OutputType([Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])]
    Param
    (
        [Parameter(ValueFromPipeline=$true, Mandatory=$true, Position=0)]
        [object] 
        $Type,

        [Parameter(Position=1)]
        [string]
        $Title,

        [Parameter()]
        [hashtable]
        $Fields,

        [Parameter()]
        [object]
        $Project,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $wit = Get-TfsWorkItemType -Type $Type -Project $Project -Collection $Collection

        $wi = $wit.NewWorkItem()

        if ($Title)
        {
            $wi.Title = $Title
        }

        foreach($field in $Fields)
        {
            $wi.Fields[$field.Key] = $field.Value
        }

        $wi.Save()

        return $wi
    }
}
<#
 
.SYNOPSIS
    Deletes a work item from a team project collection.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
.INPUTS
    Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem
    System.Int32
#>

Function Remove-TfsWorkItem
{
    [CmdletBinding(ConfirmImpact="High", SupportsShouldProcess=$true)]
    Param
    (
        [Parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        $ids = @()

        foreach($wi in $WorkItem)
        {
            if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
            {
                $id = $WorkItem.Id
            }
            elseif ($WorkItem -is [int])
            {
                $id = $WorkItem
            }
            else
            {
                throw "Invalid work item ""$WorkItem"". Supply either a WorkItem object or one or more integer ID numbers"
            }

            if ($PSCmdlet.ShouldProcess("ID: $id", "Destroy workitem"))
            {
                $ids += $id
            }
        }

        if ($ids.Count -gt 0)
        {
            $tpc = Get-TfsTeamProjectCollection $Collection
            $store = $tpc.GetService([type] "Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore")

            $errors = $store.DestroyWorkItems([int[]] $ids)
        
            if ($errors -and ($errors.Count -gt 0))
            {
                $errors | Write-Error "Error $($_.Id): $($_.Exception.Message)"

                throw "Error destroying one or more work items"
            }
        }
    }
}
<#
 
.SYNOPSIS
    Sets the contents of one or more work items.
 
.PARAMETER Project
    Specifies either the name of the Team Project or a previously initialized Microsoft.TeamFoundation.WorkItemTracking.Client.Project object to connect to. If omitted, it defaults to the connection opened by Connect-TfsTeamProject (if any).

For more details, see the Get-TfsTeamProject cmdlet.
 
.PARAMETER Collection
    Specifies either a URL/name of the Team Project Collection to connect to, or a previously initialized TfsTeamProjectCollection object.

When using a URL, it must be fully qualified. The format of this string is as follows:

http[s]://<ComputerName>:<Port>/[<TFS-vDir>/]<CollectionName>

Valid values for the Transport segment of the URI are HTTP and HTTPS. If you specify a connection URI with a Transport segment, but do not specify a port, the session is created with standards ports: 80 for HTTP and 443 for HTTPS.

To connect to a Team Project Collection by using its name, a TfsConfigurationServer object must be supplied either via -Server argument or via a previous call to the Connect-TfsConfigurationServer cmdlet.

For more details, see the Get-TfsTeamProjectCollection cmdlet.
 
#>

Function Set-TfsWorkItem
{
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline=$true, Position=0)]
        [Alias("id")]
        [ValidateNotNull()]
        [object]
        $WorkItem,

        [Parameter(Position=1)]
        [hashtable]
        $Fields,

        [Parameter()]
        [switch]
        $BypassRules,

        [Parameter()]
        [switch] 
        $SkipSave,

        [Parameter()]
        [object]
        $Collection
    )

    Process
    {
        if ($WorkItem -is [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem])
        {
            $tpc = $WorkItem.Store.TeamProjectCollection
            $id = $WorkItem.Id
        }
        else
        {
            $tpc = Get-TfsTeamProjectCollection -Collection $Collection
            $id = (Get-TfsWorkItem -WorkItem $WorkItem -Collection $Collection).Id
        }

        if ($BypassRules)
        {
            $store = New-Object 'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore' -ArgumentList $tpc, [Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStoreFlags]::BypassRules
        }
        else
        {
            $store = $tpc.GetService([type]'Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore')
        }

        $wi = $store.GetWorkItem($id)

        $Fields = _FixAreaIterationValues -Fields $Fields -ProjectName $wi.Project.Name

        foreach($fldName in $Fields.Keys)
        {
            $wi.Fields[$fldName].Value = $Fields[$fldName]
        }

        if(-not $SkipSave)
        {
            $wi.Save()
        }

        return $wi
    }
}