If you are building a web application then one of the key things that needs to be done in the build and deployment process is manipulating a remote IIS server. Your requirements could be as simple as stopping and starting a website or as far as creating websites and application pools on the fly. As I’ve previously discussed the default TFS 2010 build template activities leave much to be desired in this area (read more here). Lucky for us this is solved fairly easily with a mashup of technologies; Powershell 2.0, appcmd.exe, custom TFS build process templates and custom activities. In this simple example we will do a basic website deployment which includes stopping an existing remote website, deleting the existing files, coping our files to the deployment folder and starting the website back up…

The key to remote IIS administration is Powershell 2.0; it has the ability to run remote commands on servers using WinRM. To setup the build server and deployment server follow these steps. Note these are for Windows Server 2008 R2.
- Make sure Powershell 2.0 is installed on both the build agent and deployment server.
- Reduce the Powershell execution policy; in Powershell run the command set-executionpolicy RemoteSigned
- On the deployment server you will need to enabled remote administration. The simplest way is to run the command winrm -quickconfig and follow the basic questions (all yes). This will enabled administration on HTTP and open a hole in the firewall.
- Obviously make sure IIS in installed on the deployment machine.
- Make sure the user that will be executing remote commands has the appropriate permissions on the deployment server. For me my user was TFSSERVICE and I gave it administrator rights on the deployment server. You can probably lock the permissions down further if you like.
As a test to make sure this is working outside of the TFS build process try this…
- Create a test website (TestWebsite) on the deployment server (DeploymentServer)
- On the build server open up a command prompt and run the command: icm deploymentserver “c:\windows\system32\inetsrv\appcmd.exe stop site TestWebsite”
- On the deployment server check to see if the website is stopped; if it is then it worked and if not then you will need to debug
Once you have that working you can incorporate it into the TFS 2010 build and deployment system. To make my life easier I created a custom activity to easily execute remote commands; RemoteProcess.xaml. It wraps the InvokeProcess activity and constructs the appropriate Powershell command and handles the errors.

Now it is trivial to implement the above website deployment example. Using the RemoteProcess activity use these as the RemoteCommands and set the RemoteServer argument to DeploymentServer.
Stop Website
“c:\windows\system32\inetsrv\appcmd.exe stop site TestWebsite”
Start Website
“c:\windows\system32\inetsrv\appcmd.exe stop site TestWebsite”
You can see how powerful this is; now you have the ability to execute ANY command on the deployment server. Using this to administer IIS is just the start; this will be useful for SQL server database deployments, windows services, security… anything really.
UPDATE
After working with this for a bit I found a functional bug; the above solution does not return the remote command’s exit code. This is important so that you can have logic for success and failure of the remote command. The solution took me a long time to figure out! The new RemoteCommand should be…
“-noprofile -command “”$x = icm ” + RemoteServer + ” {” + RemoteCommand + “; $lastexitcode}; if ($x.length -gt 1){$x[0]}; exit $x[$x.length - 1]“”"
I created a few arguments on the RemoteProcess activity to support this, Output, Err and ExitCode. So to finish the above example of stopping a website would be…
powershell -noprofile -command “$x = icm DeploymentServer {c:\windows\system32\inetsrv\appcmd.exe stop site TestWebsite; $lastexitcode}; if ($x.length -gt 1){$x[0]}; exit $x[$x.length - 1]“