TFS 2015 build/release agent install and configure

Installing TFS 2015 hosted build/release agent is extremely easy:

  1. Open TFS Web Access
  2. Click on Settings in the top right corner
  3. Click on project collection in the breadcrumbs
  4. Click on Download agent link to download .zip file with build/release agent in it. Right click on downloaded .zip file, click on Properties and Unblock the files if it is blocked
  5. Now the tricky part, the installation of build/release agent is essentially unzipping the file into a folder. Please make sure that you unzip the file into a folder that is not under your user profiles (for example, Downloads or Documents) or Program files folders, because this will cause UAC to kick in when build/release job will try to call to build/release agent. So, unzip folder somewhere like D:\BuildAgent\. Once you've unzipped the file into a folder, you have installed build/release agent. Now we need to configure it.
  6. Open PowerShell (preferably as administrator), and browse to the folder where you unzipped the build/release agent
  7. Run ConfigureAgent.ps1 and follow the wizard

That's it. Easy…

Drop location in new TFS 2015 build

In the new TFS 2015/VSO build, you can save the output to the server or to the good old drop location. If you would like to use the drop location, you will need to remember to specify how you would like the output to be stored. What I mean is that you will have to specify in the build definition the folder structure you would like to create. For example, instead of \\servername\drop, you will need to specify \\servername\drop\$(Build.DefinitionName)\$(Build.BuildNumber)\

There are quite a few system/metadata variables in TFS 2015, but that will be another blog post.

UPDATE: There is now Publish Build Artifact action in new TFS Build that you should use to control where and how your build output is produced.

P.S. : If you're not using new TFS 2015/VSO build system, you should give it a try. It's awesome.

TFS and PowerShell

It has been a while since we were able to write PowerShell scripts against TFS. For those who has not tried it yet, give it a shot. It's actually very easy to use and powerful tool. For those who has not tried PowerShell yet, I strongly encourage you to do that. There is no escape, PowerShell is everywhere J

Anyways, here is what you need to do to be able to write PowerShell script against TFS:

  1. Make sure you have PowerShell 3.0 installed or better. PowerShell is part of Windows Management Framework. To get PowerShell 3.0, you need to download and install Windows Management Framework 3.0 from https://www.microsoft.com/en-ca/download/details.aspx?id=34595. You might have to reboot your machine after this install.
  2. You also to download and install Windows PowerShell Cmdlets. This tool provides a Windows PowerShell interface that supports basic version control commands and a pipeline and glue to enable scripting. Windows PowerShell Cmdlets for TFS are part of Microsoft Visual Studio Team Foundation Server Power Tools that can be found at https://visualstudiogallery.msdn.microsoft.com/f017b10c-02b4-4d6d-9845-58a06545627f. Just make sure that you pick PowerShell component during the install.

That's it. Happy scripting.

It’s back and it is going to be awesome!

ObjectSharp's At the Movies event is back in town. It's is going to be awesome! And, not just because of the good looking and courageous Captain America in the last event poster. J So, mark May 13th in your calendar and join us for the free and highly informative geek event. As usual, it will cover all the latest and greatest technologies:

  • The new TFS 2015 with its new completely overhauled build and release tools, improvements to backlog management, the kanban board, the task board, card customization and more. A lot more… And, yes, the long awaited project rename capability… Presented and demoed by Microsoft MVPs in Visual Studio ALM - Dave Lloyd and Max Yermakhanov
  • All the latest and the most excellent changes to Azure, and there are quite a few of those… Presented and demoed by Shane Castle
  • All the coolest and most amazing technical news and changes that were announced in Build 2015 that would be relevant to you now and in the near future… Presented and demoed by Lori Lalonde

As I said, it will be awesome! And, it's not just for developers. It's for DevOps as well. It's for any IT person who had a pleasure to work with Azure or Team Foundation Server. Think about, Dave's and my session will cover builds and deployments using TFS. That's DevOps and Ops. Shane's session will cover Azure. That's again, DevOps and Ops related. Lori's and Dave's session will have quite a bit of DevOps and Ops goodness too.

So, don't wait. Register today at http://www.objectsharp.com/atm! It's free! it's fun! And, you will learn a thing or two J

 

Test plan field is empty in TFS test plan progress

I spend a lot of my time nowadays helping clients successfully adopt Team Foundation Server. From planning, installation and configuration to customization, builds, release management and everything in between. And, even though, I've been working with TFS for a long time, once in a while you come across something that you have seen before. When that happens, I do my best to share my experience on this blog. So, here is my latest discovery.

The client is running a fresh install of TFS 2013 Update 4. Everything is well, except for one minor annoyance. For some reason, Test Plan field is empty in the Test Plan Progress report. There are no errors in warehouse of analysis cube processing. In fact, there are no errors in TFS, Reporting Services or Analysis Services. Every log is clean and everything runs smoothly. Typically, when you see something does not work or look properly you'd expect an error or at least a warning to show up somewhere, right? Not this time. I've looked around the web, but could not find any reasonable explanation why this is happening. I've found a few entries with people experiencing similar issue, but none provided a solution to this.

Luckily, as a Microsoft MVP in Visual Studio ALM, I have "direct" access to the product team. So, I've reached out and after a few emails back and forth, we've found a solution. It looks like that this issue can occur on fresh installs of TFS. Apparently, the Test Plan dimension loses the friendly names for some attributes when the warehouse/cubes gets processed before a project gets created. This issue can be easily fixed, if you rebuild the warehouse/cube using TFS Admin console. Clicking the Rebuild button in TFS Admin console will put everything back in its place. It's that easy. J

Pasting into Office365 OWA causes OWA to crash and close

I love Office 365 and Outlook Web Access. What's not to love?!? Excellent product with tons of amazing features for a very fair price. J Having said that, like any other good product, it can always get better. For example, I have noticed that every time when I try to copy/paste anything into the body of the email message, OWA crashes and closes with an "IE has stopped working". It closes and then recovers back to the same page. When you try to paste again, the page crashes again, and so on and so forth. This only happens when you use Internet Explorer, and copy/paste works fine in Chrome. I can always say that it's happening because "IE sucks" like a lot of people do, but I'd rather focus on finding a solution than who/what is to blame. Anyways, with a bit of internet searching I have found a work around.

  1. Go to Internet Options
  2. Click  the Security Tab
  3. Highlight the Internet zone, click Custom level button
  4. Scroll down to the Scripting section, and in the Scripting section, find Allow Programmatic clipboard access option
  5. Set Allow Programmatic clipboard access option to Enable
  6. Click OK to save
  7. Click Yes, if warning prompts comes up

Now copy/paste into the body of an email message should work just fine when you open OWA with Internet Explorer.

“Object already exists” error during Release Management server configuration

I was getting the following error while configuring RM server - "Object Already exists". Please find the log.

Database ReleaseManagement, version 12.0.30XXX.0 was installed successfully.

Created Release Management database.

Received Exception : System.Security.Cryptography.CryptographicException: Object already exists.

at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)

at System.Security.Cryptography.Utils._CreateCSP(CspParameters param, Boolean randomKeyContainer, SafeProvHandle& hProv)

at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)

at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)

at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()

at Microsoft.TeamFoundation.Release.CommonConfiguration.Helpers.CryptoHelper.ConfigureServerCryptoKey(String serverName, String databaseName)

at Microsoft.TeamFoundation.Release.Configuration.ConfigurationManager.Configure(ConfigurationUpdatePack updatePack, DelegateStatusUpdate statusListener)

at System.ComponentModel.BackgroundWorker.WorkerThreadStart(Object argument)

Work completed for GetConfiguration() call : got out of turn error

Object already exists.

 

To fix the problem, you need to make sure that the credentials used to configure the Release Management server has modify permissions on C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys. You might have to take ownership of some of the files within that folder before you can grant yourself modify permissions.

Deploy SharePoint solution in Release Management

Here is another PowerShell script that can help you deploy SharePoint solutions using Release Management. This PowerShell script can be used as a part of a custom tool/action/component in Release Management that will deploy (or first retract, then deploys) a SharePoint solution. It's fairly straightforward script that might not necessarily cover every possible scenario in SharePoint solution deployment, but it works. It takes three parameters: name of the SharePoint solution, web application name, and compatibility level of the solution. Script assumes that the wsp file is located in the same folder as the PowerShell. I know it's not perfect, but it can be easily modified to use full path to the wsp file instead.

param

(

[string]$WebApp = $null,

[string]$WSP_FileName = $null,

[string]$CompatibilityLevel = $null

)

 

function WaitForJobToFinish([string]$Identity)

{

$job = Get-SPTimerJob | ?{ $_.Name -like "*solution-deployment*$Identity*" }

$maxwait = 30

$currentwait = 0

if (!$job)

{

Write-Host -f Red '[ERROR] Timer job not found'

}

else

{

$jobName = $job.Name

Write-Host -NoNewLine "[WAIT] Waiting to finish job $jobName"

while (($currentwait -lt $maxwait))

{

Write-Host -f Green -NoNewLine .

$currentwait = $currentwait + 1

Start-Sleep -Seconds 2

if (!(Get-SPTimerJob $jobName)){

break;

}

}

Write-Host -f Green "...Done!"

}

}

 

function RetractSolution([string]$Identity, [string]$web_application, [string]$compatibility_level)

{

Write-Host "[RETRACT] Uninstalling $Identity"

Write-Host -NoNewLine "[RETRACT] Does $Identity contain any web application-specific resources to deploy?"

$solution = Get-SPSolution | where { $_.Name -match $Identity }

if($solution.ContainsWebApplicationResource)

{

Write-Host -f Yellow "...Yes!"

Write-Host -NoNewLine "[RETRACT] Uninstalling $Identity from $web_application web application"

Uninstall-SPSolution -identity $Identity -CompatibilityLevel $compatibility_level -WebApplication $web_application -Confirm:$false -ErrorVariable uninstallSolution

}

else

{

Write-Host -f Yellow "...No!"

Uninstall-SPSolution -identity $Identity -Confirm:$false

}

if ($uninstallSolution.Count -ne 0)

    {

        throw "Uninstalling SharePoint solution failed."

    }

else

{

Write-Host -f Green "...Done!"

}

WaitForJobToFinish

Write-Host -NoNewLine '[UNINSTALL] Removing solution:' $SolutionName

Remove-SPSolution -Identity $Identity -Force -Confirm:$false -ErrorVariable removeSolution

if ($removeSolution.Count -ne 0)

    {

        throw "Removing SharePoint solution failed."

    }

else

{

Write-Host -f Green "...Done!"

}

}

 

function DeploySolution([string]$Path, [string]$Identity, [string]$web_application, [string]$compatibility_level)

{

Write-Host -NoNewLine "[DEPLOY] Adding solution:" $Identity

Add-SPSolution $Path -ErrorVariable addSolution

if ($addSolution.Count -ne 0)

        {

            throw "Adding SharePoint solution failed."

        }

else

{

Write-Host -f Green "...Done!"

}

Write-Host -NoNewLine "[DEPLOY] Does $Identity contain any web application-specific resources to deploy?"

$solution = Get-SPSolution | where { $_.Name -match $Identity }

if($solution.ContainsWebApplicationResource)

{

Write-Host -f Yellow "...Yes!"

Write-Host -NoNewLine "[DEPLOY] Installing $Identity for $web_application web application"

Install-SPSolution -Identity $Identity -CompatibilityLevel $compatibility_level -WebApplication $web_application -GACDeployment -Force -ErrorAction Stop -ErrorVariable installSolution

}

else

{

Write-Host -f Yellow "...No!"

Write-Host -NoNewLine "[DEPLOY] Globally deploying $Identity"

Install-SPSolution -Identity $Identity -GACDeployment -Force -ErrorAction Stop -ErrorVariable installSolution

}

    if ($installSolution.Count -ne 0)

    {

        throw "Installing SharePoint solution failed."

    }

else

{

Write-Host -f Green "...Done!"

}

WaitForJobToFinish

}

 

$snapin = Get-PSSnapin | Where-Object { $_.Name -eq "Microsoft.SharePoint.Powershell" }

if ($snapin -eq $null) {

Write-Host "[INIT] Loading SharePoint Powershell Snapin"

Add-PSSnapin "Microsoft.SharePoint.Powershell"

}

 

$identity = $WSP_FileName

$path = $WSP_FileName

Write-Host "[INFO] ----------------------------------------"

Write-Host "[INFO] Installing $Identity"

Write-Host -NoNewLine "[INFO] Determining if $Identity is already installed"

 

$isInstalled = Get-SPSolution | where { $_.Name -eq $identity }

if ($isInstalled)

{

Write-Host -ForegroundColor Yellow "...Yes!"

(RetractSolution $identity $WebApp $CompatibilityLevel)

(DeploySolution $path $identity $WebApp $CompatibilityLevel)

}

else

{

Write-Host -ForegroundColor Yellow "...No!"

(DeploySolution $path $identity $WebApp $CompatibilityLevel)

}

Write-Host -NoNewline "[INFO] Installation and deployment of $Identity"

Write-Host -ForegroundColor Green "...Done!"

 

##################################################################################

# Indicate the resulting exit code to the calling process.

if ($exitCode -gt 0)

{

"`nERROR: Operation failed with error code $exitCode."

}

"`nDone."

exit $exitCode

 

Here is a link to download the script.

Backup SharePoint solution before deploying its new version using Release Management

Just wanted to share the PowerShell script to backup SharePoint solutions using Release Management. This script can be used as a part of a custom tool/action in Release Management that will backup existing SharePoint solution before deploying a new version of this solution. This tool/action could come in handy when you would like to set up rollback activities for when SharePoint solution install goes sideways. I think it's a good idea to back up things. You know, just in case…

Here is a script. It's not the most sophisticated PowerShell script, but it gets the job done. It takes two parameters: name of the SharePoint solution and the destination folder where you would like to store the backed up solution file.

param

(

[string]$WSP_FileName = $null,

[string]$DestinationName = $null

)

# Load SharePoint snap-in

$snapin = Get-PSSnapin | Where-Object { $_.Name -eq "Microsoft.SharePoint.Powershell" }

if ($snapin -eq $null) {

Write-Host "[INIT] Loading SharePoint Powershell Snapin"

Add-PSSnapin "Microsoft.SharePoint.Powershell"

}

 

Write-Host "[INFO] ----------------------------------------"

Write-Host "[INFO] Backing up $WSP_FileName"

$farm = Get-SPFarm

$file = $farm.Solutions.Item("$WSP_FileName").SolutionFile

$BackupPath = Join-Path $DestinationName $WSP_FileName

if ($file.Count -ne 0)

    {

$file.SaveAs("$BackupPath")

Write-Host -f Green "...Backup complete!"

    }

else

{

    throw "$WSP_FileName solutiuon was not found."

}

 

##################################################################################

# Indicate the resulting exit code to the calling process.

if ($exitCode -gt 0)

{

"`nERROR: Operation failed with error code $exitCode."

}

"`nDone."

exit $exitCode

 

Here is a link to download the script.

Release Stuck in Pending State

Recently, I have come across an interesting behavior in TFS Release Management. When you kick off new release, the release gets stuck in Pending state on certain custom components. And, it stays in that state "forever". Obviously, the first thing that comes to mind is that deployment agent is not responding (even though it does not really make sense since if the agent became unresponsive the component deployment task would time out eventually), but you go ahead and try to restart the deployment service running on the target server anyways. It does not help, of course. So, you start taking other "desperate" measures like re-configuring deployment agent or restarting the target server, but nothing works. I'm calling those measures "desperate" because, deep down in your heart, you know that there is nothing wrong with the target server and that the problem lies somewhere else. You just don't know where, so you resort to the old "Have you tried turning it off and on" approach. We all do it...

Anyways, after a bunch of digging around, I have finally discovered a pattern when this problem occurs. Imagine the following scenario:

  1. You create a custom component and add it to your release template
  2. You kick off your release template
  3. You then realize that you need to tweak your custom component, so you go ahead and tweak your custom component, then kick off your release template again with your recent changes to the component.

This is a very typical continuous improvement approach. You make a change to your custom component, save it and the next time release has been triggered your changes to component will take effect. It works every time in Release Management. Well, almost every time. Apparently, if you change one of the configuration variables in your components from Standard type to Encrypted type (and vice versa), save your component and trigger release, then the release will get stuck in Pending state on that component. Not sure why this is happening. Perhaps, the hash of the component changes or something. Anyways, to fix the issue, you need to:

  1. Remove the component in question completely from your release template, including a link to the component. Then, save the release template
  2. Reopen release template and re-link the component in question
  3. Re-add the component in question, and re-enter the values for your configuration variables.
  4. Save the release template
  5. Trigger a new release. Release should now successfully deploy the component in question

To me, this looks like a bug to me and, hopefully, Microsoft will address this in the next update(s) of the Release Management Server. I am sure they will.

P.S.: This is my first blog post as a Microsoft MVP in Visual Studio ALM. Looking forward to writing a lot more… Hurray!!!