In the series the following parts have been published
- Part 1: Introduction
- Part 2: Add arguments and variables
- Part 3: Use more complex arguments
- Part 4: Create your own activity
- Part 5: Increase AssemblyVersion
- Part 6: Use custom type for an argument
- Part 7: How is the custom assembly found
- Part 8: Send information to the build log
- Part 9: Impersonate activities (run under other credentials)
- Part 10: Include Version Number in the Build Number
- Part 11: Speed up opening my build process template
- Part 12: How to debug my custom activities
- Part 13: Get control over the Build Output
- Part 14: Execute a PowerShell script
- Part 15: Fail a build based on the exit code of a console application
- Part 16: Specify the relative reference path
Update: If you want to use the TFS Object Model in the activity code, check the following post: http://blogs.msdn.com/b/taylaf/archive/2009/12/04/introducing-tfs-impersonation.aspx. It gives you the ability to execute TFS request on behalf on someone else without providing a password.
There are situation in which you want to run your activity under other credentials, which is also called impersonation. This could be the case for example when you deploy your solution to the development environment.
To achieve the impersonation of the an activity we need to be able to specify the credentials in an argument of the build. Because you don’t want that the password is visible, we need to specify a custom type. This process is covered in Customize Team Build 2010 – Part 6: Use custom type for an argument.
Secondly we need to impersonate. To achieve this I create a class with that logs on as a different user in the constructor and in the destructor (dispose method) the user is logged off again.
using System.Runtime.InteropServices;
using System.Security.Principal;
using System;
using Achmea.Build.Tasks.CustomType;
namespace Achmea.Build.Tasks.Library
{
public class Impersonation : IDisposable
{
private WindowsImpersonationContext _impersonatedUser = null;
private IntPtr _userHandle;
public Impersonation(Credential credentials)
{
if (credentials != null && !string.IsNullOrEmpty(credentials.UserName))
{
_userHandle = new IntPtr(0);
bool returnValue = LogonUser(credentials.UserName, credentials.Domain, credentials.Password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _userHandle);
if (!returnValue)
throw new ApplicationException("Could not impersonate user");
WindowsIdentity newId = new WindowsIdentity(_userHandle);
_impersonatedUser = newId.Impersonate();
}
}
#region IDisposable Members
public void Dispose()
{
if (_impersonatedUser != null)
{
_impersonatedUser.Undo();
CloseHandle(_userHandle);
}
}
#endregion
#region Interop imports/constants
public const int LOGON32_LOGON_INTERACTIVE = 2;
public const int LOGON32_LOGON_SERVICE = 3;
public const int LOGON32_PROVIDER_DEFAULT = 0;
[DllImport("advapi32.dll", CharSet = CharSet.Auto)]
public static extern bool LogonUser(String lpszUserName, String lpszDomain, String lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public extern static bool CloseHandle(IntPtr handle);
#endregion
}
}
You can now easily impersonate an activity by surrounding the code of the activity by constructing the Impersonation class in the first line, and dispose it at the last line. In C# you can make it even easier when you use the “using” statement
using System.Activities;
using Achmea.Build.Tasks.CustomType;
using Achmea.Build.Tasks.Library;
using Microsoft.TeamFoundation.Build.Client;
namespace BuildTasks.Activities
{
[BuildActivity(HostEnvironmentOption.Agent)]
public class CopyFile : CodeActivity
{
public InArgument<Credential> Credentials { get; set; }
protected override void Execute(CodeActivityContext context)
{
using (Impersonation impersonation = new Impersonation(context.GetValue(this.Credentials)))
{
// Insert your activity code over here
}
}
}
}
You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.