1

I am trying to deploy a bunch of WPF applications in CI using TFS. Until now, the deployment step was manually activated, i.e I called a Powershell script from my dev. box to run through each project and deploy. If it helps, here is the code snippet.

$projs = Get-ChildItem -Path $pwd -Recurse -Include '*.csproj
foreach ($proj in $projs)
{

    $xml = [xml](Get-Content $proj)
    $assemblyName=""
    $publishUrl = ""
    $productName =""

    $nodes = $xml.GetElementsByTagName('AssemblyName')
   #Write "Trying to get AssemblyName"
   foreach ($node in $nodes) {
       $oldName = $node.'#text'
       if($oldName.Contains("Beta")){continue}
       $newName =$oldName+'_Beta'
        #skip any PublishUrl that is still the default 'publish\'
    #   Write $newName
       $node.'#text' = $newName
       $assemblyName = $newName
       }
   #Write "Trying to get ProductName"
   $nodesProduct = $xml.GetElementsByTagName('ProductName')
   foreach ($node in $nodesProduct) {
       if($node.'#text'.Contains(".NET"))
           {
           continue
           }
       $oldName = $node.'#text'
      if($oldName.Contains("Beta")){continue}
       $newName =$oldName+'_Beta'
    #   Write $newName
       $node.'#text' = $newName
       $productName = $newName
       }
   #Write "Trying to get PublishURL"
   $nodesPublish = $xml.GetElementsByTagName('PublishUrl')
   foreach ($node in $nodesPublish) {
       $oldName = $node.'#text'
       #skip any PublishUrl that is still the default 'publish\'
       if ($node.'#text' -eq 'publish\')  { break }
       if($oldName.Contains("Beta")){continue}
       $newName =$oldName+'Beta\'
    #   Write $newName
       $node.'#text' = $newName
       $publishUrl = $newName
       }
   #if all three params are not null save and deploy project
   if($assemblyName -ne"" -And $publishUrl -ne "" -And $productName -ne "" )
    {
        $xml.Save($proj)
        Write "trying to deploy $productName to $publishUrl"
        msbuild /m /t:publish /p:Configuration='Debug' /p:Platform=AnyCPU /p:ApplicationVersion=$appVersion /p:ApplicationRevision=$Revision /p:MinimumRequiredVersion=$newVersion /p:PublishUrl="$publishUrl" /verbosity:m $proj
            $pubDir = Join-Path $proj.Directory -ChildPath "bin\Debug\app.publish" -Resolve -ErrorAction Stop
            #copy the files to the publish URL
            Write "$pubDir"
            Copy-Item -Path "${pubDir}\*" -Destination "$publishUrl" -Include '*.*' -Recurse -Force
            Copy-Item -Path "${pubDir}\Application Files" -Destination "$publishUrl" -Recurse -Force
        tf vc undo /noprompt $proj 
        Write "Tf undone"
    }` 

Please ignore all the Beta stuff as I change my Assembly-info.cs to have a development and production environment deployment separate. I've generated my own certificate and linked it to my .csproj files. This works and has been tested and is our current strategy. I want to integrate this script as a Post Process Action in Team Foundation Server so we can get CD.

On the server, I have:

  1. VSTS running as my admin account
  2. My pfx certs installed on the server

This same script generates the following error:

\(x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(2884,5): warning MSB3327: Unable to find code signing certificate in the current user's Windows certificate store. To correct this, either disable signing of the ClickOnce manifest or install the certificate into the certificate store.

\(x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(4961,5):  MSB4044: The "SignFile" task was not given a value for the required parameter "CertificateThumbprint". 

I have noticed that the .csproj that the TFS service copied onto the agent does not have the linkage to the imported certificates (which are also in source control)

So far, I have tried installing the certificates on the server itself and have also tried running as NTService. More information on this error can be found in these threads 1 , 2 , 3. However, neither of their solutions seem to work. I would appreciate any help.

Suhas Anjaria
  • 120
  • 1
  • 11
  • 1
    Have you tried just build your source (for all of projects) by tfs and then sign this build with your own certificate, clickone manifest using the `mage.exe`? Of course, it's only alternative way to get that you want. – George Alexandria Sep 06 '17 at 22:27
  • If I were to do that, I could just keep my current system, which builds the sources in tfs and I use the PS script to deploy. My objective is to completely automate delivery, so it can be run without any developer intervention, either using a gated check-in or time based triggers. Unless I am missing something. – Suhas Anjaria Sep 07 '17 at 12:34
  • You also can write PSScripts to sign manifest and certificate using `mage.exe` for my example above. So this solution is completely automate delivery. – George Alexandria Sep 07 '17 at 18:12
  • I see. I have limited experience with mage, so forgive my perceived ignorance of your solution. Thanks for your input, I managed to solve the issue without a lot of code change! – Suhas Anjaria Sep 11 '17 at 13:22

1 Answers1

0

This is what i ended up doing to make it work.

  1. Added my pfx as Linked File to all my UI projects

  2. Made all projects use the certificate from file from this menu

  3. Checked it into source control

  4. Made a new build definition who's only job is to run my powershell snippet

  5. Ran the build under my account on TFS

Suhas Anjaria
  • 120
  • 1
  • 11