Why can I not configure TFS Build Service in unattend mode via Powershell DSC?

做~自己de王妃 提交于 2019-12-12 15:07:48

问题


With the following DSC configuration (snippet of the resources section only, cut out preamble, diagnostics, and Start-DscConfiguration parts 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 configure the TFS Build Service in unattended mode is as follows (I've taken out logging, error checking, and diagnostics for the purpose of 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
}

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

Apart from the TFS Build Service configuration block, I can run my DSC configuration successfully against all of my build agents.

However, when I attempt to run my TFS Build Service configuration block, my DSC configuration 'succeeds' however the unattended configuration of the service 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 a Project Collection Administrator on the TFS service, there is no issue with permissions. I've proven that by successfully running the configuration script locally on an agent machine and being successful there.

I realize that there is no double-hop permissions allowed with PowerShell, but since DSC executes on the agent involved, there shouldn't be an issue of double-hop credentials and the permissions would be allowed to be relayed to the TFS service for registration.

Maybe I've missed something more trivial?

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


回答1:


You may still be running into double-hop issues. DSC requires WinRM, even when run in Push mode, because no matter what it's "remoting" into the machine when it executes the configuration. That still counts as a hop.

Consider these 2 executions:

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

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

The first invocation should work (no remoting is being done with that parameter set). The second should fail with a permission error.



来源:https://stackoverflow.com/questions/26304425/why-can-i-not-configure-tfs-build-service-in-unattend-mode-via-powershell-dsc

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!