Recently, we were in need of executing a command on a remote server as part of our automated build process. For this we decided to make use of Windows Management Instrumentation (WMI). Before jumping to the code, copying and pasting it, there are always some security issues that need to be addressed. For this task there are also some service configurations that are required on the remote machine.

Note: All of the following settings are configured on the remote machine on which the command will be run remotely.

Security

Follow the steps below to set the WMI permissions for the build service account:

  1. Click on Start > Control Panel > Administrative Tools > Computer Management.
  2. Expand Service and Applications.
  3. Right-click on WMI Control and click on Properties.
  4. On the property dialog select the Security tab.
  5. Expand Root > CIMV2.
  6. Click on the Security button.
  7. Click on Add and add <TFSSERVICE> account.
  8. In the list of permissions, allow the following permissions:
    • Execute methods
    • Remote enable
  9. Click on OK.

Follow the step below to set the Local Security Policy for the build service account:

  1. Click on Start > Control Panel > Administrative Tools > Local Security Policy.
  2. Expand Local Policies > User Rights Assignment.
  3. Find and double-click on Log on as a service.
  4. Click on Add User or Group and add <TFSSERVICE> account.
  5. Click on OK.
  6. Find and double-click Log on as a batch job.
  7. Click on Add User or Group and add <TFSSERVICE> account.
  8. Click on OK and close the Local Security Policy window.

Services

Follow the steps below set the dependent services to automatically start:

  1. Click on Start > Control Panel > Administrative Tools.
  2. Double click on Services.
  3. Ensure that the following services are Started, and are set to start Automatic.
    • COM+ Event System
    • Remote Access Auto Connection Manager
    • Remote Access Connection Manager
    • Remote Procedure Call (RPC)
    • Remote Procedure Call (RPC) Locator
    • Remote Registry
    • Server
    • Windows Management Instrumentation
    • Windows Management Instrumentation Driver Extensions
    • WMI Performance Adapter
    • Workstation
  4. Close the services dialog.

Here is the code for the build task that will execute a command on a remote machine:

/// <summary>
/// Executes a command line on a remote machine.
/// </summary>
public class RemoteExec : Task
{
 /// <summary>
 /// Initialises a new instance of the <see cref="RemoteExec"/> class.
 /// </summary>
 public RemoteExec()
 {
   RemoteMachine = Environment.MachineName;
 }

 /// <summary>
 /// Gets or sets the name of the machine on which to execute the command.
 /// </summary>
 public string RemoteMachine
 {
   get;
   set;
 }

 /// <summary>
 /// Gets or sets the command to execute on the remote machine.
 /// </summary>
 [Required]
 public string Command
 {
   get;
   set;
 }

 /// <summary>
 /// Executes the task on the remote machine.
 /// </summary>
 /// <returns>true if the task succeeded, otherwise, false</returns>
 public override bool Execute()
 {
   if (string.IsNullOrEmpty(Command))
   {
     Log.LogError("Command property was not set.");
     throw new ArgumentNullException("Command");
   }

   var connOptions = new ConnectionOptions();
   connOptions.Impersonation = ImpersonationLevel.Impersonate;
   connOptions.EnablePrivileges = true;

   var managementScope = new ManagementScope(
     string.Format(@"\\{0}\ROOT\CIMV2", RemoteMachine), connOptions);
   managementScope.Connect();

   Log.LogMessage(string.Format(CultureInfo.CurrentCulture, "Connected to {0}: {1}",
   RemoteMachine, managementScope.IsConnected));

   if (!managementScope.IsConnected)
   return false;

   var objectGetOptions = new ObjectGetOptions();
   var managementPath = new ManagementPath("Win32_Process");
   var processClass = new ManagementClass(managementScope, managementPath, objectGetOptions);

   var processParameters = processClass.GetMethodParameters("Create");

   processParameters["CommandLine"] = Command;
   try
   {
     var outParams = processClass.InvokeMethod("Create", processParameters, null);
     var processID = Convert.ToUInt32(outParams["processId"]);

     Log.LogMessage(string.Format(CultureInfo.CurrentCulture,
       "Creation of the process {0} returned: {1}", processID, outParams["returnValue"]));

     var stopQuery = new WqlEventQuery(string.Format(CultureInfo.CurrentCulture,
       "select * from Win32_ProcessStopTrace where ProcessID={0}", processID));

     var processStopEvent = new ManagementEventWatcher(managementScope, stopQuery);
     processStopEvent.Options.Timeout = new TimeSpan(0, 1, 0);

     Log.LogMessage("Waiting for process to complete...");
     processStopEvent.WaitForNextEvent();
     processStopEvent.Stop();

     Log.LogMessage("Completed.");
   }
   catch (Exception ex)
   {
     Log.LogError(ex.Message);
   }

   return true;
   }
}

The task can then be used as follows:

<UsingTask TaskName="RemoteExec" AssemblyFile="BuildTasks.dll"/>
<RemoteExec RemoteMachine="$(Server)" Command="application.exe" />

There we have it, executing a command remotely from MsBuild!


With our build process we decided on a deployment folder structure that required us to create NTFS Junction Points. Junction Points are links to other folders, also known as soft links. Below is an example of how these links appear in Windows 7. It also shows our deployment folders for various build types:

JunctionPointFolderStructureAll the folders with shortcut arrows are junction points or links to folders in the Published folder. For each build, the binaries are copied to a build numbered folder in the Published folder. Only when a build is successful; meaning that all code compiled and unit tests passed; do we update the junction point to the relevant build numbered folder in Published.

By using the code written by Jeff Brown in this article, I was able to create a custom build task that enabled us to the create and delete junction points with relative ease. Here is a link to the source code for an MsBuild task that will enable you to manage junction points with MsBuild.


In our build process, using Team Foundation Build, we decided to use ClickOnce for application deployment. In this post I’ll try to set the lay of the land. In the following couple of posts I will take you through the configuration of a clickonce deployment.

Choosing the deployment strategy

There are essentially two different ways in which you can deploy a clickonce application. They are:

  1. Physical media such as CD or DVD
  2. Network share or web

Deciding on the strategy that will work for you is largely determined by the available bandwidth at the client site. If there is none to very little bandwidth, or no internet connectivity, choose CD / DVD. Otherwise choose Network share or web.

We opted for the web strategy and hence the posts will be based around the configuration of this strategy.

Lay of the land

Assume that we have one build server and one deployment server. The build server will push the build artifacts to the deployment server where clients will use ClickOnce to install the application from the deployment server.

To make the explanations easier we will setup a hypothetical configuration and base the deployment configuration on it. Our hypothetical solution is made up of two projects, Project1 and Project2. Project 1 is in its second version, v1.0.0.1 and Project2 is in its first version, v1.0.0.0. For each of the projects a subfolder is created in the Solution folder and in turn, a version folder for each release of the project.

Below is a diagram that demonstrates this configuration:

ClickOnceBasicConfig

Gotcha 1: ClickOnce does not allow sub-folders within the version folders. In other words, you cannot have a folder Solution\Project1\v1.0.0.0\AnotherFolder\AndAnotherFolder.

Initial configuration

First of all we need a folder on the deployment server to push the build artifacts to. For this, a Solution folder is created on the deployment server and shared with modify permissions granted to the TFSSERVICE account. Remember the TFSSERVICE account that is used by the TFS Build service?

Futhermore we need to configure Internet Information Services (IIS) to interpret the ClickOnce files correctly according to type. For this the following MIME types must be added to the website that is going to be used when deploying the solution:

.application    application/x-ms-application
.manifest       application/x-ms-manifest
.deploy         application/octet-stream

If you are using IIS 6.0 have a look at this article “IIS 6.0 Does Not Serve Unknown MIME Types”.

Next, I’ll discuss the different files that describe the application and deployment.


greentickIncluded in the Team Foundation Server Tools download is an absolute must-have, Team Foundation Build Notification. If you have are making use of continuous integration chances are that you are building often. Instead of keeping an eye out for the latest build report in your email or constantly checking it in Visual Studio, use this notification utility. It has little popups that appear when someone requested a build either via checkin or ad hoc, which is configurable. It has a notification icon in the system tray (one the few that I will tolerate) and changes whenever one of the builds succeeds, fails or starts. It gives immediate access to the build log which you would normally have to browse for. It is also able to monitor multiple builds. A definite win!


nhibernate-intellisenseUsing NHibernate requires the writing of some tedious XML-based configuration mapping files. Remembering all the tags and attributes can sometimes be overwhelming. Thankfully the contributors decided to include intellisense hints, which are in nhibernate-configuration.xsd and nhibernate-mapping.xsd.

In order to have the hints available in Visual Studio 2008 copy the files into C:\Program Files\Microsoft Visual Studio 9.0\XML\Schemas and restart Visual Studio.


In the excellent book Pragmatic Thinking and Learning by Andy Hunt, he suggests that every programmer should have a personal wiki in order to manage knowledge effectively. A sort of exocortex. A place where you can keep ideas, thoughts and nearly anything you want outside your brain.

Ever received one of those emails that you just have to keep somewhere? That snippet of source code that might come in handy? That chocolate muffin recipe? Why not put all of it into your wiki?

My personal choice of this kind of wiki is TiddlyWiki. Simply because all of the content is in a single HTML file. Fan of Getting Things Done? TiddlyWiki can easily be configured to support the Getting Things Done methodology. Have a look at d-cubed for example.

Bear in mind that it has a learning curve to it, but if you are willing to stick to it you will surely reap the benefits.

Some of the features include:

  • Tagging
  • Searching
  • Text formatting, including support for monospace
  • Highlighting
  • Block quotes
  • Tables
  • Headers
  • Save with backups
  • RSS feeds

I would suggest the following plugins to really spice-up TiddlyWiki:

Check out TiddlyTools and TiddlyVault for other plugins. It supports themes, which can be downloaded from TiddlyThemes. There is also a great cheat sheat available.


In Team Foundation Server 2008, there doesn’t seem an easy way to simply perform a rollback on a comitted changeset. Well, that is until you discover the power of the updated Team Foundation Server Power Toys.

rollback-changeset

Rollback command

Before rolling back a changeset, the local workspace must have no pending changes. After issuing the rollback command, tfpt rollback a dialog will appear asking whether you want the local workspace brought up to date with the repository. After affirming the dialog, a get command will be issued for your workspace and updated with the latest changes.

After the get operation completed successfully, another dialog will appear asking you to identify the changeset that you want to rollback. Note: Make sure that you have the correct changeset before continuing.

Select the files that you want to rollback in the changeset and click on “Roll Back”. After the rollback completed, you might have to resolve some conflicting changes. Now that the rollback is complete, you will still need to commit the new changeset, which is the latest code, without the changeset that was rolled back.

If you want to skip all of the GUI stuff, then you can simply execute the rollback command this way: tfpt rollback /changeset:4018.


AWOL CD-ROM

22Feb09

For the second time now I have had the CD-ROM drive on my HP nw8440 disappear from Windows. The Device Manager reports the following for the CD-ROM drive: “Windows cannot load the device driver for this hardware. The driver may be corrupted or missing. (Code 39)”. Why? It was perfect yesterday and today it is missing or corrupted? Weird. According to the Microsoft Knowledge Base article it can happen after removing a CD or DVD burning program.

Although the error is rather annoying, there is a simple fix for it. I have replicated the steps here for your convenience:

Step 1: Start Registry Editor

Start Registry Editor.

Step 2: Delete the UpperFilters registry entry

  1. In Registry Editor, expand My Computer, and then expand HKEY_LOCAL_MACHINE.
  2. Expand SYSTEM, and then expand CurrentControlSet.
  3. Expand Control, and then expand Class.
  4. Under Class, click {4D36E965-E325-11CE-BFC1-08002BE10318}.
  5. In the details pane of Registry Editor, on the right side, click UpperFilters.Note You may also see an UpperFilters.bak registry entry. You do not have to remove that entry. Click UpperFilters only.
    • If you see the UpperFilters registry entry in the details pane of Registry Editor, go to step 6.
    • If you do not see the UpperFilters registry entry, you still might have to remove the LowerFilters registry entry. To do this, go to “Step 3: Delete the LowerFilters registry entry.”
  6. On the Edit menu, click Delete.
  7. Click Yes when you receive the following message:

    Are you sure you want to delete this value?

The UpperFilters registry entry is removed.

Step 3: Delete the LowerFilters registry entry

  1. In the details pane of Registry Editor, on the right side, click LowerFilters.Note You might see a LowerFilters.bak registry entry. You do not have to remove that entry. Click LowerFilters only.

    If you do not see the LowerFilters registry entry, unfortunately this content is unable to help you any more. Go to the “Next Steps” section for information about how you can find more solutions or more help on the Microsoft Web site.

  2. On the Edit menu, click Delete.
  3. Click Yes when you receive the following message:

    Are you sure you want to delete this value?

    The LowerFilters registry entry is removed.

  4. Exit Registry Editor.

The article recomends restarting the computer after deleting the two registry entries, but I have found that it works fine without restarting.


Lately I’ve been thinking on morale in the workplace. What is morale? According to Alexander H. Leighton, “morale is the capacity of a group of people to pull together persistently and consistently in pursuit of a common purpose“.

From this quote, it is evident that if morale decreases, people will no longer pull together in pursuit of the common purpose. Following from that, we can then say that morale is the glue that keeps people united and focused on the given task.

Sustaining a healthy level of morale in the workplace should be one of the primary concerns of managers. I’d like to think that every workplace has a set of morale pumps that help to maintain a certain level of morale, whether it be great coffee, job security or an energizing work culture, which contribute to keeping employees focused and united.

In the current economic environment where most businesses have to consider cutting costs on most levels, be careful when cutting costs on the morale pumps. Consider the cost of reducing and taking away that which maintains this level of morale. I think investing into keeping morale high is probably more needed now than ever before.

Here are some factors that influence morale in the workplace, either positively or negatively :

  • Job security;
  • Management style;
  • Staff feeling that their contribution is valued by their employer;
  • Realistic opportunities for merit-based promotion;
  • Team composition;
  • The work culture;
  • Compensation;
  • Recognition and rewards;
  • Work that isn’t challenging;
  • Limited growth opportunities;
  • Fun environment to work in

Making use of either Team System Web Access or Team Explorer you might find it necessary to edit some of the work item templates. At first it might seem very confusing but is quite straight forward.

When editing work item templates there are two tools that you need to know about, witimport and witexport. They are used to import and export specific work item templates from an existing Team Foundation Server project.

First, you need to export the bug work item template by using the following command line:

witexport /f <work item templates folder>
    /t <tfs server>:8080 /p <project name> /n bug

This will create a bug.xml template file in the work item templates folder specified, which could be any folder that you have access to.

The first part of the XML file defines the fields (indicated by the fields tag) that describe the bug. A workflow process (indicated by the workflow tag) is described in the middle of the file and the bottom part of the file describes the layout (indicated by the form tag) of the bug submission form.

Let’s add an environment field to the template that will indicate the environment where the bug occurred with the following values, tip, pre-stage, stage and live:

<field name="Environment" refname="TfsProject.Environment" type="String">
    <required />
    <helptext>Was the bug found in tip, pre-stage, stage or live?</helptext>
    <allowedvalues>
	<listitem value="Tip"/>
	<listitem value="Pre-stage"/>
	<listitem value="Stage"/>
	<listitem value="Live"/>
    </allowedvalues>
    <default from="value" value="Pre-Stage"/>
</field>

The above piece of XML can be put anywhere after a closing field tag or the opening fields tag and must be somewhere before the workflow opening tag.

Name is obviously the name of the field that we are giving the additional piece of information. RefName is the name of this field that we are going to use to refer to when setting up the control in the layout section of the file. The presence of required tag says that a value must be specified for this field and will be validated automatically when a new bug is submitted. Next, we supply a list of values that will appear in the drop down list. Finally we provide a default value that will automatically be selected for each bug submission.

We now have to specify the new look of the form with our additional field and is done with the following XML definition:

<group>
    <column PercentWidth="50">
        <control Type="FieldControl" FieldName="TfsProject.Environment" Label="&Environment:" LabelPosition="Left" />
    </column>
    <column PercentWidth="50">
        ...
    </column>
</group>

A group defines a collection of controls that are related. The column tag has an attribute that states the percentage space that the control should occupy. Each group should add up to to 100% but do not have to. The fieldname should be set to the field that we have just created in the fields section of the template. The label attribute is set to the label that we want to show in front of the control. In this case it is “Environment:”.

After placing the control, all that is left is to save the bug.xml file and import it back into Team Foundation Server. This is accomplished by the following command line:

witimport /f <work item templates folder>\bug.xml
    /t <tfs server>:8080 /p <project name>

After a successful import the changes should be visible from both TSWA (Team System Web Access) and Team explorer, by double clicking on the Bug work item template.

Go customise those work item templates!