Skip to content

Instantly share code, notes, and snippets.

@jstangroome
Created September 29, 2013 00:01
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jstangroome/6747950 to your computer and use it in GitHub Desktop.
Save jstangroome/6747950 to your computer and use it in GitHub Desktop.
Serialize a TFS 2012 Build Definition as XML to be version controlled
[CmdletBinding()]
param (
$CollectionUri,
$ProjectName
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName 'Microsoft.TeamFoundation, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Build.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
# consider scanning HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\Visual Studio v11.0 Reference Assemblies
#Add-Type -AssemblyName 'Microsoft.TeamFoundation.Build.Workflow, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Add-Type -Path 'C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Build.Workflow.dll'
$Collection = [Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory]::GetTeamProjectCollection($CollectionUri)
$BuildServer = $Collection.GetService([Microsoft.TeamFoundation.Build.Client.IBuildServer])
$Definitions = $BuildServer.QueryBuildDefinitions($ProjectName)
$Def = $Definitions | ? { $_.queuestatus -eq 'enabled' } | select -skip 3 -First 1
function Convert-BuildDefinitionToXml {
[CmdletBinding()]
param (
[Microsoft.TeamFoundation.Build.Client.IBuildDefinition]
$Definition,
[string]
$CollectionUri
)
$x = [xml]'<BuildDefinition />'
# TODO build def uri, collection uri, team project name?
$x.DocumentElement.AppendChild($x.CreateElement('Uri')).InnerText = $Definition.Uri
$x.DocumentElement.AppendChild($x.CreateElement('Id')).InnerText = $Definition.Id
$x.DocumentElement.AppendChild($x.CreateElement('TeamProject')).InnerText = $Definition.TeamProject
$x.DocumentElement.AppendChild($x.CreateElement('CollectionUri')).InnerText = $CollectionUri
# general
$x.DocumentElement.AppendChild($x.CreateElement('Name')).InnerText = $Definition.Name
$x.DocumentElement.AppendChild($x.CreateElement('Description')).InnerText = $Definition.Description
$x.DocumentElement.AppendChild($x.CreateElement('QueueStatus')).InnerText = $Definition.QueueStatus
# trigger
$triggerX = $x.DocumentElement.AppendChild($x.CreateElement('Trigger'))
$triggerX.AppendChild($x.CreateElement('TriggerType')).InnerText = $Definition.TriggerType
$triggerX.AppendChild($x.CreateElement('ContinuousIntegrationType')).InnerText = $Definition.ContinuousIntegrationType
$triggerX.AppendChild($x.CreateElement('ContinuousIntegrationQuietPeriodMinutes')).InnerText = $Definition.ContinuousIntegrationQuietPeriod
$triggerX.AppendChild($x.CreateElement('BatchSize')).InnerText = $Definition.BatchSize
foreach ($Schedule in $Definition.Schedules) {
$scheduleX = $triggerX.AppendChild($x.CreateElement('Schedule'))
$scheduleX.AppendChild($x.CreateElement('DaysToBuild')).InnerText = $Schedule.DaysToBuild
$scheduleX.AppendChild($x.CreateElement('StartTimeSecondsPastMidnight')).InnerText = $Schedule.StartTime
$scheduleX.AppendChild($x.CreateElement('TimeZone')).InnerText = $Schedule.TimeZone
$scheduleX.AppendChild($x.CreateElement('Type')).InnerText = $Schedule.Type
# TODO serialize TimeZoneInfo as culture-invariant
}
#workspace
# TODO optional path translation
$workspaceX = $x.DocumentElement.AppendChild($x.CreateElement('Workspace'))
foreach ($Mapping in $Definition.Workspace.Mappings) {
$mappingX = $workspaceX.AppendChild($x.CreateElement('Mapping'))
$mappingX.AppendChild($x.CreateElement('MappingType')).InnerText = $Mapping.MappingType
$mappingX.AppendChild($x.CreateElement('ServerItem')).InnerText = $Mapping.ServerItem
$mappingX.AppendChild($x.CreateElement('LocalItem')).InnerText = $Mapping.LocalItem
$mappingX.AppendChild($x.CreateElement('Depth')).InnerText = $Mapping.Depth
}
#build defaults
$controllerX = $x.DocumentElement.AppendChild($x.CreateElement('BuildController'))
$controllerX.AppendChild($x.CreateElement('BuildControllerUri')).InnerText = $Definition.BuildControllerUri
$controllerX.AppendChild($x.CreateElement('Name')).InnerText = $Definition.BuildController.Name
$controllerX.AppendChild($x.CreateElement('Description')).InnerText = $Definition.BuildController.Description
$controllerX.AppendChild($x.CreateElement('CustomAssemblyPath')).InnerText = $Definition.BuildController.CustomAssemblyPath
$x.DocumentElement.AppendChild($x.CreateElement('DefaultDropLocation')).InnerText = $Definition.DefaultDropLocation
# process
$processX = $x.DocumentElement.AppendChild($x.CreateElement('Process'))
$processX.AppendChild($x.CreateElement('Id')).InnerText = $Definition.Process.Id
$processX.AppendChild($x.CreateElement('Description')).InnerText = $Definition.Process.Description
$processX.AppendChild($x.CreateElement('ServerPath')).InnerText = $Definition.Process.ServerPath
$processX.AppendChild($x.CreateElement('SupportedReasons')).InnerText = $Definition.Process.SupportedReasons
$processX.AppendChild($x.CreateElement('TeamProject')).InnerText = $Definition.Process.TeamProject
$processX.AppendChild($x.CreateElement('TemplateType')).InnerText = $Definition.Process.TemplateType
$processX.AppendChild($x.CreateElement('Version')).InnerText = $Definition.Process.Version
# TODO use WorkflowHelpers.DeserializeProcessParameters to translate paths but serialize as-is
$parametersX = $x.DocumentElement.AppendChild($x.CreateElement('ProcessParameters'))
[void]$parametersX.AppendChild( $x.CreateCDataSection( $Definition.ProcessParameters) ) # TODO escape ]] in parameters
<#
$Dictionary = [Microsoft.TeamFoundation.Build.Workflow.WorkflowHelpers]::DeserializeProcessParameters($Definition.ProcessParameters)
#>
# retention policy
$policyListX = $x.DocumentElement.AppendChild($x.CreateElement('RetentionPolicyList'))
foreach ($Policy in $Definition.RetentionPolicyList) {
$policyX = $policyListX.AppendChild($x.CreateElement('RetentionPolicy'))
$policyX.AppendChild($x.CreateElement('BuildReason')).InnerText = $Policy.BuildReason
$policyX.AppendChild($x.CreateElement('BuildStatus')).InnerText = $Policy.BuildStatus
$policyX.AppendChild($x.CreateElement('DeleteOptions')).InnerText = $Policy.DeleteOptions
$policyX.AppendChild($x.CreateElement('NumberToKeep')).InnerText = $Policy.NumberToKeep
}
# TODO attached properties at the various levels of the hierarchy?
return ,$x
}
$buildxml = Convert-BuildDefinitionToXml -Definition $Def -CollectionUri $CollectionUri
$buildxml.Save('c:\temp\build.xml')
gc 'c:\temp\build.xml'
@jzajac2
Copy link

jzajac2 commented Mar 5, 2014

Curious, would you expect this to work with TFS 2010 if the assemblies to load for Add-Type were changed to version '10.0.0.0' (and the -Path changed to 10.0 folder)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment