Why can't I configure the TFS Build Service in unattended install mode via Powershell DSC?

With the following DSC configuration (resource section snippet only, cut preamble, diagnostics and Start-DscConfiguration components for 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"
        }

      

My script to set up a TFS Build Service in unattended mode looks like this (I took log, error checking and diagnostics with SO purpose):

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
}

      

I can successfully run script Configure-TfsBuildService.ps1 on any of my Windows 2012 R2 build agents as long as I am logged in locally.

Besides the TFS Build Service configuration block, I can successfully complete my DSC configuration for all of my build agents.

However, when I try to start my TFS build service configuration block, my DSC configuration "succeeds", however, the service autoconfiguration fails with the following log message:

[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] -----------------------------------------------------

      

Since I am running the DSC configuration with my own credentials and I am the project collection administrator on the TFS service, there are no permissions issues. I have proven this by successfully executing the script configuration locally on the agent machine and executing it successfully.

I understand that double-swap permissions are not allowed with PowerShell, but since DSC is running on the agent involved, there should be no double-swap credential issues and the permissions are allowed to pass the service to TFS for registration.

Maybe I missed something more trivial?

EDIT: A description of TFS 2012/2013 unattended installation can be found here: http://blogs.msdn.com/b/visualstudioalm/archive/2012/10/12/unattended-installation-of-team-foundation-server-2012.aspx

+3


source to share


1 answer


You may still run into double hop issues. DSC requires WinRM, even when running in Push mode, because whatever it "deletes" into the machine when it does the configuration. It still counts as a jump.

Consider these 2 designs:



$sb = { Get-Content \\server\share\file.txt }

Invoke-Command -ScriptBlock $sb
Invoke-Command -ComputerName . -ScriptBlock $sb

      

The first call should work (no deletions are made with this parameter set). The second should fail with a permission error.

+1


source







All Articles