Download files from TFS server with PowerShell

If you want to download files from TFS with PowerShell, you will need to write a script that can access the TFS Server and access the folder on your drive.

This script uses a server path in the TFS server and download some files under that server path to the drop folder of your build. If you don’t use a build, you can change then environment variables. This script is created because of an original question on StackOverflow.

# The deploy directory for all the msi, zip etc.
$AutoDeployDir = "Your TFS Directory Server Path"
$deployDirectory = $($Env:TF_BUILD_DROPLOCATION + "\Deploy\" + $Env:TF_BUILD_BUILDNUMBER)

# Add TFS 2013 dlls so we can download some files
Add-Type -AssemblyName 'Microsoft.TeamFoundation.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
Add-Type -AssemblyName 'Microsoft.TeamFoundation.VersionControl.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
$tfsCollectionUrl = 'http://YourServer:8080/tfs/YourCollection' 
$tfsCollection = New-Object -TypeName Microsoft.TeamFoundation.Client.TfsTeamProjectCollection -ArgumentList $tfsCollectionUrl
$tfsVersionControl = $tfsCollection.GetService([Microsoft.TeamFoundation.VersionControl.Client.VersionControlServer])

# Register PowerShell commands
Add-PSSnapin Microsoft.TeamFoundation.PowerShell

# Get all directories and files in the AutoDeploy directory
$items = Get-TfsChildItem $AutoDeployDir -Recurse

# Download each item to a specific destination
foreach ($item in $items) {
    # Serverpath of the item
    Write-Host "TFS item to download:" $($item.ServerItem) -ForegroundColor Blue

    $destinationPath = $item.ServerItem.Replace($AutoDeployDir, $deployDirectory)
    Write-Host "Download to" $([IO.Path]::GetFullPath($destinationPath)) -ForegroundColor Blue

    if ($item.ItemType -eq "Folder") {
        New-Item $([IO.Path]::GetFullPath($destinationPath)) -ItemType Directory -Force
    }
    else {
        # Download the file (not folder) to destination directory
        $tfsVersionControl.DownloadFile($item.ServerItem, $([IO.Path]::GetFullPath($destinationPath)))
    }
}

 

TFS delete build definition timeout

When you do a tfs delete on a build definition and you receive a timeout, you probably have to many builds in your TFS server. Even if you delete all the build for your build definition, tfs still stores all the builds in your TFS Server. Just like your TFS Team projects, you have to delete and then destroy the builds. After that, you could delete the build definition completely.

The only way to do this is, is to delete and destroy the builds in pieces. You can only do that by the command prompt.

I created a PowerShell script that loops through the builds for a specific build definition and deletes all the builds before a specific date. So if your build is maybe a year old, you could start the script a year back from now and loop through all the builds until let’s say two months ago. You could skip the number of days you want. I set the days to skip to 15 because I have a lot of builds each month and otherwise the TFS server has trouble to delete the bigger chunks.

$TfsCollectionUrl = "http://YourTfsServer:8080/tfs/YourTeamCollection"
$teamProject = "YourTeamProject"
$BuildDefinition = "YourTeamBuildDefinitionName"

Function CountForward {
    Param([datetime]$startDate,[int]$daysToSkip,[datetime]$endDate)

    Write-Host "Count forward from:" $startDate.ToString("yyyy-MM-dd") -foregroundcolor "magenta"
    Write-Host "Count forward until:" $endDate.ToString("yyyy-MM-dd")-foregroundcolor "magenta"
    Write-Host "Count every" $daysToSkip "day(s)" -foregroundcolor "magenta"

    while ($startDate -le $endDate) {
        $BuildDefinitionFull = $teamProject + "\" + $BuildDefinition
        $dateToQuery = $startDate.ToString("yyyy-MM-dd")

        Write-Host "Delete and destroy Builds before" $startDate.ToString("yyyy-MM-dd") "for build definition" $BuildDefinitionFull -foregroundcolor "magenta"
        
        tfsbuild.exe delete /server:$TfsCollectionUrl /builddefinition:"$BuildDefinitionFull" /daterange:~$dateToQuery /deleteoptions:All /noprompt /silent
        tfsbuild.exe destroy /server:$TfsCollectionUrl /builddefinition:"$BuildDefinitionFull" /daterange:~$dateToQuery /noprompt /silent
        
        $startDate = $startDate.AddDays($daysToSkip)
    }
}
CountForward -startDate (get-Date).AddDays(-300) -daysToSkip 15 -endDate (get-Date).AddDays(-60)

Save the PowerShell file as “DeleteBuildDefinition.ps1” and execute it in your Visual Studio command prompt. You can execute the PowerShell file in your VS command prompt with the following command:

PowerShell -Command "& {D:\DeleteBuildDefinition.ps1}"

tfs delete build definition timeout

Update TypeMock version with AutoDeploy enabled

We use TypeMock in a project. We also use the TypeMock AutoDeploy feature so we can use different versions of TypeMock on one build server. The AutoDeploy feature of TypeMock makes it possible to run your unit tests on the build server without installing TypeMock on the build server. You can read about this feature in my other blog post:

 

https://www.locktar.nl/programming/embed-typemock-in-your-tfs-build-definition

 

Because we are using VS2013 now, we had to upgrade the TypeMock version to a new Release Candidate version that I got from TypeMock for testing. When we where testing, we saw that the tests where failing because the old version was referenced in the AutoDeploy folder. So we had to update the TypeMock version in source control to keep the AutoDeploy functionality working on the build server. After some tries, I now have a best practice for update TypeMock.

 

  1. Uninstall TypeMock (not always necessary but for this Release Candidate they advised me to do it)
  2. Install your new version of TypeMock (you whole team off course)
  3. Search for your AutoDeploy folder in the root of your project and check it out of TFS
  4. Open your solution and go to the TypeMock menu and choose “Fix references…”
  5. Choose the second radio button that says “Copy libraries from installation folder to:” and browse to your AutoDeploy folder of step 3
  6. Hit ok. Now every test project that uses TypeMock will be modified with the new TypeMock version. The TypeMock folder in the AutoDeploy folder now also has the new version of the dll.
  7. If some of the projects have a TypeMock references to your program files, you have to change it. This is needed because otherwise the AutoDeploy feature isn’t working. To fix this, you have to delete the reference and add a new one. Browse for the right dll to the TypeMock folder in the AutoDeploy folder in the root of your project. Repeat this for every reference in every project that has the wrong path.
  8. Browse with Windows Explorer to your TypeMock installation directory in program files. In this installation directory you will also find an AutoDeploy folder. Copy all the files in that folder and overwrite your old TypeMock version files in the AutoDeploy folder in the root of your project. 
  9. Check everything in and test your build

 When you followed these steps, you have the new TypeMock version in your project in minutes. 

Typemock Settings

Embed Typemock in your TFS Build definition

When you want to test your code that uses Typemock, you can use a Team Foundation Server Build Server. The current version of Typemock is 7.4 and this version (introduced in 6.2) has the AutoDeploy feature included. This is very important because now you can use multiple versions of Typemock on one Build server. The reason for that is that you don’t have to install Typemock on you build server anymore. To setup Typemock Autodeploy, you can use the tutorial on their help page in the chapter: Typemock Isolator Integration with Team Foundation Server 2010 (TFS). The only thing that they forgot to mention in the documentation is that there is generated a Typemock directory with a couple of dll’s in it inside your just added AutoDeploy directory. This is done after you fixed the references and restarted Visual Studio. Don’t forget to checkin that directory.

In the help documentation, they say that you have to use the workflow of Typemock to get the AutoDeploy to work. The customer that I now work for already have a custom workflow. I just created that workflow last week with some custom actions for them. So I want to integrate the custom Typemock stuff in the workflow of the customer. The customer works with TFS 2010 (just migrated a few months ago from 2008 so they have a lot of catching up to do) so this blog is aimed at TFS Build 2010. But this will also work for 2012. You can also check the documentation about Typemock with TFS 2012 on their website.

 

The differences between the build templates

There only 4 differences between the template that are special for Typemock. I will show them beneath. The only thing that you have watch for is the right place to put custom activities on the right place.

First open your own workflow in the designer. In your toolbox, add a new category and choose the TypeMock.TFS2010.dll assembly in the installation directory of your Typemock version on your machine. After that, three custom activities are added to your toolbox. Don’t forget to reference the dll in your project where your custom workflow is located.

image

Now add the activities on the right place by dragging them into the workflow. You don’t have to edit any properties. On the left side, you see the default template of TFS 2010. On the right side the template of Typemock. Drag the activities on the same place in your own workflow.

Registreren Typemock

Stoppen Typemock

After that, add a workflow argument of the TypemockSettings type. You can optionally edit the Metadata argument to customize the text that you will see in you build definition.

Typemock arguments

Save your workflow and checkin your workflow. Restart Visual Studio and configure the license in your build definition.

That’s it! It’s very easy. It is not more than 10 minutes of work to edit your own template. When you run your build now with the AutoDeploy feature on and with entering the right license info in your build definition, the build will succeed en will test your Typemock tests.

TFS connection Value cannot be null

In our company, we are upgrading from TFS 2010 to TFS 2012. So to test everything we have a clone of the TFS server.

To test the clone I had to switch my connection to the different servers. After hitting the “Connect” button I got a “Value cannot be null.” exception. It said that also that: “Parameter name: baseUri” was the problem. After contacting a colleague of me, he said to delete the cache of the TFS server on my computer. After doing that, the connection worked as it suppose to work.

You can find the cache in the following folder: C:Users<yourusername>Local SettingsApplication DataMicrosoftTeam Foundation2.0Cache

Creating a TFS Build definition with deploying

This week I was busy to give our environment more quality by adding a deployment of the newly checked in work. This was a quite more difficult then I imagined before I started. This is because the environment that we have is off course not completely the same as the standard demos of Microsoft and the documentation for this is… not available?

 

Team project setup

We have a Team project with 3 different branches.image

  1. Production (Release)
  2. Staging
  3. Development (Debug)

Off course we develop in the Development branch. When the iteration is finished, we merge everything to the staging environment where we and the customer could test everything. When testing (and bug fixing if you made bugs) is done we merge everything to production. In that way we can do bug fixes directly on every version of the project.

 

Build definitions

We wanted to have a build definition for development that:

  1. Builded the solution;
  2. Deploys the multiple projects to the different locations.

I created for each branch a different build definition with different needs to get to the result. I will explain the Development because this build definition will publish multiple ASP .NET Web Applications to different IIS websites.

 

Creating the build definition for development

imageCreate a new build definition and give it the name that you want. I called it Development because I want to use it only on my Development branch in the team project.

I set the trigger to go off on each check-in. In that way, the build will also publish all new versions of the web applications to the desired environments on the server(s).

image

Set the workspace to the workspace of your branch.

Define a drop location and which build controller you like to use of your build server. Maybe you have a dedicated build controller for particular solutions that have many check-ins.

Setup deployment to the server

The last part is the part where we setup the deployment to the server.

image

Define on step 1 the Configurations that you want to build. With config transformations you could setup the different build environments. See for a tutorial this following link:

http://www.asp.net/mvc/tutorials/deployment/deployment-to-a-hosting-provider/Deployment-to-a-Hosting-Provider-Web-Config-File-Transformations-3-of-12

Because it is a development environment, we use the default Debug config with all the links to the test database and test web services. Set the projects to build to the solution file.

 

Note for building only one project
When you set the projects to build to only one project, you could get an error when you are building. The error will say something about your output path that is not right.

c:WindowsMicrosoft.NETFramework64v4.0.30319Microsoft.Common.targets (484): The OutputPath property is not set for project ‘UI.Web.Mvc.csproj’.  Please check to make sure that you have specified a valid combination of Configuration and Platform for this project.  Configuration=’Debug’  Platform=’Any CPU’.  You may be seeing this message because you are trying to build a project without a solution file, and have specified a non-default Configuration or Platform that doesn’t exist for this project.

image

This isn’t really the cause why you would get that error. When you open your project file (unload your project and right click to edit) you will see that the build platform is AnyCPU and not Any CPU. You will have to change the “Configurations to Build” in your build definition to AnyCPU. You can just type it in the dialog.

imageWhen you have a whole solution to build, you don’t need to do this.

 

 

 

 

 

 

Setup deployment for only one web application

When you have only one web application, you can add the “MSBuild Arguments” in your build definition directly.

See for a large explanation for each build argument the following blog:

http://vishaljoshi.blogspot.nl/2010/11/team-build-web-deployment-web-deploy-vs.html

The arguments that you typically have to use are the following:

/p:DeployOnBuild=True
/p:DeployTarget=MsDeployPublish
/p:MSDeployServiceURL=http://servername
/p:DeployIISAppPath=”Default Web Site”
/p:CreatePackageOnPublish=False
/p:MsDeployPublishMethod=RemoteAgent
/p:AllowUntrustedCertificate=True
/p:UserName=username
/p:Password=password

 

Setup deployment for multiple web applications

If you have multiple web applications in a solution (like we have), you can’t use the build arguments like above because then every application would be publishing to the same website on the same server. This will fail your build definition eventually. Maybe not the first time but it will fail sometime. For me it failed every second time I tried it.

Well stop the complaining and tell me how to fix this!

Change the build arguments that you have setup above. Only use the following build arguments:

/p:DeployOnBuild=True
/p:CreatePackageOnPublish=False

image

 

Now unload your projects that you want to publish and edit every project file to their specific needs. Go to the PropertyGroup of your build configuration that you are using in your build definition. I use Debug so will change that PropertyGroup.

image

Use the same name as the build arguments and enter your values.

 

Note for exposing your publish username and password
When you setup your deployment, you have to enter your username and password. Otherwise you will get an error that your not authenticated.

C:Program Files (x86)MSBuildMicrosoftVisualStudiov10.0WebMicrosoft.Web.Publishing.targets (3588): Web deployment task failed.(Remote agent (URL http://servername/MSDEPLOYAGENTSERVICE) could not be contacted.  Make sure the remote agent service is installed and started on the target computer.) Make sure the site name, user name, and password are correct. If the issue is not resolved, please contact your local or server administrator. Error details: Remote agent (URL http://servername/MSDEPLOYAGENTSERVICE) could not be contacted.  Make sure the remote agent service is installed and started on the target computer. An unsupported response was received. The response header ‘MSDeploy.Response’ was ” but ‘v1’ was expected. The remote server returned an error: (401) Unauthorized.

For security reasons, you should not enter your username and password in your build definition. So, how to fix this?

The first thing you must do is give your TFS build service account rights to the server that your publishing to. I added it for now to the local Administrators group of my old (but still working) Windows  Server 2003 server.

The second thing that you have to do depends on which way you have setup your arguments. Use the following syntax for the build arguments in your build definition:
/p:UserName=

And for in your project file:
image

This will indicate that the username and password that will be used for deploying is the same as your build controller on your build server.

Hopefully I gave you enough information about deploying your applications. If you have any questions, don’t hesitate to contact me.

 

Update:
When you deployed your project and see the zip with your project in it, you should check your connectionstring in your config. It could be the case that the connectionstring is using parameters to generate the full connectionstring. This is an option that is on by default. If it is using parameters, you will see something like “$(Replaceable Token…)”.

You can simple disable this (so it will use the connectionstring that you have set in your config transform) by adding the <AutoParameterizationWebConfigConnectionStrings>False</AutoParameterizationWebConfigConnectionStrings> tag in your project file on the same place where you placed the rest of the properties.

Add Area and Iterations permissions in TFS 2010

IMG_16639mkIf you want to give your user permissions to add Areas and Iterations, you could that be following these steps:

Area

  1. Go to: Team –> Team Project Settings –> Areas and Iterations…
  2. Select on the “Area” tab the “Security…” button on the bottom
  3. Select or add the group/person that you want to give the permissions
  4. Set “Create and order child nodes” to allow

Optional: Set “Delete this node” and/or “Edit this node” to allow for edit and delete permissions.

Iteration

  1. Go to: Team –> Team Project Settings –> Areas and Iterations…
  2. Select on the “Iteration” tab the “Security…” button on the bottom (this is a different button than on the “Area” tab.
  3. Select or add the group/person that you want to give the permissions
  4. Set “Create and order child nodes” to allow

Optional: Set “Delete this node” and/or “Edit this node” to allow for edit and delete permissions.

Undo pending changes on a file in Team Foundation Server

Ralph Jansen BlogIn this small tutorial I will explain how to undo pending changes on a file on your Team Foundation Server. I tested this code on a Team Foundation Server 2010 edition.

First you need the name of the workspace that is locking your file on the server. To accomplish this you can run the following code in the Visual Studio Command Prompt:

tf workspaces /owner:<developers_logonname> /computer:* /server:<your TFS server>

After you have found your workspace name, you can undo the changes for the file with the following code:

tf undo "$/<Path to file to undo>" /workspace:<Workspace name>;<Domain and username> /s:<your TFS server>

 

Note:

  1. Your TFS servername must be with http and the portnumber to succeed.
  2. You can find the path to file simply by clicking the properties on the file in the “Source Control Explorer” window

If you followed the above steps, you will see the following message in the command prompt.
image