Со следующей конфигурацией DSC (только фрагмент раздела ресурсов, вырезанные части преамбулы, диагностики и Start-DscConfiguration для SO):
Package TFSServer2013 {
Name = "Microsoft Team Foundation Server 2013 Update 3 (x64)"
Path = '$InstallerPath\Team Foundation Server 2013\tfs_server.exe'
Arguments = "/quiet"
Credential = $Credential
Ensure = "Present"
ProductID = "B516BA7C-3C20-3FCC-B130-B42058ABF87A"
}
File TFSUserFile {
DestinationPath = "$Env:TEMP\TFSConfig\TfsUserName.clixml"
Attributes = "Hidden"
SourcePath = $TFSUsernameFile
Ensure = "Present"
Force = $true
Credential = $Credential
Type = "File"
MatchSource = $true
}
File TFSPasswordFile {
DestinationPath = "$Env:TEMP\TFSConfig\TfsUserPassword.clixml"
Attributes = "Hidden"
SourcePath = $TFSUserPasswordFile
Ensure = "Present"
Force = $true
Credential = $Credential
Type = "File"
MatchSource = $true
}
File TfsBuildAgentConfigureScript {
DestinationPath = "$LocalInstallerPath\PowerShell\Configure-TfsBuildService.ps1"
SourcePath = "$POSModulePath\Configure-TfsBuildService.ps1"
Ensure = "Present"
Force = $true
Credential = $Credential
Type = "File"
MatchSource = $true
}
Script TFSConfigure {
SetScript = "
. C:\BuildAgent\Installers\PowerShell\Configure-TfsBuildService.ps1
Setup-TfsBuildService -ConfigIniFile 'C:\BuildAgent\Logs\TfsConfig.ini' -TfsBuildControllerName 'TFSMASTER' -TfsServiceUri 'http://mytfsservice:8080/tfs/My_Collection' -TfsUsernameClixml ""`$Env:TEMP\TFSConfig\TfsUserName.clixml"" -LogFilesPath 'C:\BuildAgent\Logs' -TfsUserPasswordClixml ""`$Env:TEMP\TFSConfig\TfsUserPassword.clixml""
if (`$false) { Remove-Item -Force -Path ""$Env:TEMP\TFSConfig\TfsUserPassword.clixml"" }
"
TestScript = "
New-EventLog -LogName 'Windows Powershell' -Source DSC -ErrorAction SilentlyContinue
Write-EventLog -LogName 'Windows PowerShell' -Source DSC -EntryType Information -EventId 1 -Message ""Testing if TFS build service is up and running.""
`$srv = Get-WmiObject -Class Win32_Service | Where-Object -FilterScript { (`$PSItem.Name -ne `$null) -and (`$PSItem.Name.Equals(""TFSBuildServiceHost.2013"")) }
return (`$srv -ne `$null)
"
GetScript = "
New-EventLog -LogName 'Windows Powershell' -Source DSC -ErrorAction SilentlyContinue
`$ensure='Absent'
if (Test-Path 'C:\BuildAgent\Logs\TfsConfig.ini' -ErrorAction Ignore) { `$ensure = 'Present' }
Write-EventLog -LogName 'Windows PowerShell' -Source DSC -EntryType Information -EventId 1 -Message ""TFSConfigure GetScript (C:\BuildAgent\Logs\TfsConfig.ini): Ensure=`$ensure""
@{Ensure=`$ensure}
"
Credential = $Credential
DependsOn = "[File]TFSPasswordFile","[File]TFSUserFile","[Package]TFSServer2013","[File]TfsBuildAgentConfigureScript"
}
Мой сценарий для настройки службы сборки TFS в автоматическом режиме выглядит следующим образом (для SO я удалил ведение журнала, проверку ошибок и диагностику):
Function Setup-TfsBuildService
{
Param(
[Parameter(Mandatory=$true)]
[string]
$ConfigIniFile,
[Parameter(Mandatory=$true)]
[string]
$TfsBuildControllerName,
[Parameter(Mandatory=$true)]
[string]
$TfsServiceUri,
[Parameter(Mandatory=$true)]
[string]
$TfsUsernameClixml,
[Parameter(Mandatory=$true)]
[string]
$LogFilesPath,
[Parameter(Mandatory=$true)]
[string]
$TfsUserPasswordClixml,
[Parameter()]
[string]
$TfsConfigExePath="$Env:ProgramFiles\Microsoft Team Foundation Server 12.0\Tools\TfsConfig.exe"
)
if (Test-Path -Path $TfsUsernameClixml)
{
$tfsuser = (Import-CliXml -Path $TfsUsernameClixml)
}
else { return }
Remove-Item -Force -Path $ConfigIniFile -ErrorAction SilentlyContinue
# Stop any existing TFS 2013 build service
if (Get-Service -Name "TFSBuildServiceHost.2013" -ErrorAction Ignore)
{
$srv = Get-WmiObject -Class Win32_Service | Where-Object -FilterScript { ($PSItem.Name -ne $null) -and ($PSItem.Name.Equals("TFSBuildServiceHost.2013")) }
$srv.StopService() | Out-Null
$srv.Delete() | Out-Null
}
# Create the unattend file:
$inputparams = "ConfigurationType=scale;AgentCount=1;ExistingControllerName=$TfsBuildControllerName;CleanResources=True;CollectionUrl=$TfsServiceUri;IsServiceAccountBuiltIn=False;ServiceAccountName=$tfsuser"
$tfsconfoutput = & $TfsConfigExePath unattend /create /type:build /unattendfile:"$ConfigIniFile" /inputs:$inputparams 2>&1
$tfsconfoutput | Out-File -FilePath (Join-Path $LogFilesPath "TfsConfigUnattendFile.log") -Force
# Install the service:
$Error.Clear()
$tfsuserpswd = (Import-CliXml -Path $TfsUserPasswordClixml)
$tfsconfoutput = & $TfsConfigExePath unattend /configure /unattendfile:"$ConfigIniFile" /inputs:"ServiceAccountPassword=$tfsuserpswd" /continue 2>&1
Remove-Variable tfsuserpswd
$tfsconfoutput | Out-File -FilePath (Join-Path $LogFilesPath "TfsInstallUnattend.log") -Force
}
Я могу успешно запустить сценарий Configure-TfsBuildService.ps1 на любом из моих агентов сборки Windows 2012 R2, если я вошел в систему локально.
Помимо блока конфигурации службы сборки TFS, я могу успешно запустить свою конфигурацию DSC для всех моих агентов сборки.
Однако, когда я пытаюсь запустить блок конфигурации службы сборки TFS, моя конфигурация DSC «успешна», однако автоматическая конфигурация службы завершается со следующим сообщением в журнале:
[Info @15:40:47.754] +-+-+-+-+-| Verifying that the running account has required Team Foundation Server permissions |+-+-+-+-+-
[Info @15:40:47.754] Starting Node: TBPERMISSIONS
[Info @15:40:47.754] NodePath : VINPUTS/Progress/Conditional/TBPERMISSIONS
[Error @15:40:47.920]
Exception Message: TF30063: You are not authorized to access http://mytfsservice:8080/tfs/My_Collection. (type TeamFoundationServerUnauthorizedException)
Exception Stack Trace: at Microsoft.TeamFoundation.Client.Channels.TfsHttpWebRequest.SendRequest()
at Microsoft.TeamFoundation.Client.Channels.TfsHttpRequestChannel.Request(TfsMessage message, TimeSpan timeout)
at Microsoft.TeamFoundation.Client.Channels.TfsHttpClientBase.Invoke(TfsClientOperation operation, Object[] parameters, TimeSpan timeout, Object[]& outputs)
at Microsoft.TeamFoundation.Framework.Client.LocationWebService.Connect(Int32 connectOptions, Int32 lastChangeId, Int32 features)
at Microsoft.TeamFoundation.Framework.Client.FrameworkServerDataProvider.Connect(ConnectOptions connectOptions)
at Microsoft.TeamFoundation.Admin.AuthenticatedCollectionProvider.Microsoft.TeamFoundation.Admin.IAuthenticatedCollectionProvider.GetAuthenticatedConnection()
at Microsoft.TeamFoundation.Admin.VerifyPermissionsToConfigure.Run(ActivityContext context)
Inner Exception Details:
Exception Message: The remote server returned an error: (401) Unauthorized. (type WebException)Status: ProtocolError
Response Status Code: Unauthorized
Response Status Message: Unauthorized
Exception Stack Trace: at System.Net.HttpWebRequest.GetResponse()
at Microsoft.TeamFoundation.Client.Channels.TfsHttpWebRequest.SendRequestAndGetResponse(HttpWebRequest webRequest, WebException& webException)
[Info @15:40:47.920] Node returned: Error
[Error @15:40:47.920] TF30063: You are not authorized to access http://mytfsservice:8080/tfs/My_Collection.
[Info @15:40:47.920] Completed BuildServicePermissions: Error
[Info @15:40:47.920] -----------------------------------------------------
Поскольку я запускаю конфигурацию DSC со своими учетными данными и являюсь администратором коллекции проектов в службе TFS, проблем с разрешениями нет. Я доказал это, успешно запустив сценарий конфигурации локально на машине агента и добившись там успеха.
Я понимаю, что в PowerShell не разрешены разрешения с двойным переходом, но поскольку DSC выполняется на задействованном агенте, не должно быть проблем с учетными данными двойного перехода, и разрешения будут разрешены для передачи в службу TFS для регистрации. .
Может быть, я пропустил что-то более тривиальное?
РЕДАКТИРОВАТЬ: описание автоматической установки TFS 2012/2013 можно найти здесь: http://blogs.msdn.com/b/visualstudioalm/archive/2012/10/12/unattended-installation-of-team.-foundation-server-2012.aspx