Using MSDeploy to automate your Enterprise Application remote deployments.

MsDeploy is a newish technology that is a bit schizophrenic.  What I mean is that it is a tool that is useful to both Developers and Administrators but it is not clear from the documentation how to best use the technology and how to approach it. I believe it stated as a Server Administrator tool and the team was able to work in an integration with Visual Studio which made it into a more robust framework, but at the same time left is command line interface with so many options that it is challenging to get a grasp on.  To top that off the Web Platform Installer uses the MsDeploy packages as a way to distribute packages through that tool.  After working through some various ways to use the technology I have settled into some commands that work well for our projects.


Let me set the context of how we are using the tool and what we already had in place so that you can better understand if my use of MsDeploy will work for you. At Headspring we use Continuous Integration on all of our projects and as a result, once our software is built by our build server the next logical step is to deploy our software to a server and than run User Interface tests against the application. Most of our projects are web applications running on ASP.Net MVC using Sql Server as the back end.  We install our software using a lightweight zipfile that contains the web application files, database migration scripts and a deployment script which can poke config files and execute our database migration tool.  We already have all the pieces in place to deploy our application on a local machine.


Up until know we have used two methods to deploy instances to remote machines.  The first methods was to install Cruise Control.Net on the server and have it monitor our source control repository for a new installation package being committed to the repository. Once it sees a new package CCNet will pull down the package, install it locally and go on its merry way.  The second method, is to kick off the deployment from the build server and connect over the network to the target database to run upgrades and then xcopy the files to a unc share.  Both of these methods require setting up some configuration on our target servers. My goal with our deployments is to reduce the amount of per server configuration we do on each server and use some conventions to make each server look similar to one from a different project.


Using MSDeploy allows us to do the following.

1. Remove the need to install cruise control on the target server and update the configuration for cruise control on each target server.  We do have to install MSDeploy on each server but we do not have to mess with any configuration after that.

2. We do not have to mess with setting up unc shares and deal with the mess.  It sounds like a silly thing but by getting away from the unc share we can also test our deployments from any machine and msdeploy is actually firewall friendly.  xcopy to a unc share is not firewall friendly which means that we cannot use it for all of our clients which means variations between our projects. 

3. We use msdeploy as a mechanism to distribute our deployment packages and then remotely execute the packages.  This means I can have a single instance of our Continuous Integration server which reduces the number of places to maintain configuration.  That is a big win.  This also means the log files for all of the deployments can be tracked in a single place.

4. Another benefit of using msdeploy to push our deployments means that I can easily setup new instances of a test configuration and push it to multiple servers without having to log into each machine.. This is good for efficiency.

Our use of MSDeploy now boils down to two steps.  Distribute and Execute.  We have some of our scripts in NAnt and we are in the process of migrating to PowerShell now that version 2.0 is available from the older operating systems.  Below is a sample of executing msdeploy from a NAnt script.

Calling MsDeploy from Nant


The dirPath  command tells MSDeploy to synchronize a directory from the source computer a target computer. This is a pretty easy command to understand.

The second command is the runCommand this command was added between the RC and 1.0 release of MSDeploy and I am so happy they added it. The run command is told to execute a command on the remote machine.  Since we are running installation scripts, they do not execute instantly and as a result the waitInterval and waitAttempts need to be specified so that the command does not timeout before it has completed running. other than that the output of the console application is piped back to the source computer.  The one caveat about the run command is that when it starts it runs from the C:windowssystem32 directory.  In order to work around this issue I have found that passing the directory of the command into the batch file that I run allows my batch files to first cd to that directory as its first step.  This is a pretty harmless thing to do and works pretty well.

This is what a sample deployment batch files looks like.

cd %1
rd ..codeToDeploy /s /q
applicationNamePackage.exe -o..CodeToDeploy -y
cd ..CodeToDeploy
cmd /c %systemroot%system32inetsrvappcmd stop site applicationName_dev
call dev.bat
cmd /c %systemroot%system32inetsrvappcmd start site applicationName_dev

This is pretty basic and does some IIS commands as well. 


I am sure I left some information out, but I wanted to get a brain dump of our use of MSDeploy.


Long term I would like to see the use of PowerShell driving msdeploy and adding some configuration around each Server Role in an application and tie it to the servers needed for each environment.  I have started a project to put this together called psTrami but I have not put any of the code together yet, just some small spikes to prove it out.


More to come sometime soon…..

About Eric Hexter

I am the CTO for QuarterSpot. I (co)Founded MvcContrib, Should, Solution Factory, and Pstrami open source projects. I have co-authored MVC 2 in Action, MVC3 in Action, and MVC 4 in Action. I co-founded online events like mvcConf, aspConf, and Community for MVC. I am also a Microsoft MVP in ASP.Net.
This entry was posted in Asp.Net, CC.Net, continous integration, Deployment, MSDeploy, Open Source Software, Tools. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Eddie Cianci

    Hi Eric,

    Do you use MSDeploy for hot & cold deployments (upgrade vs install)? Currently when we do a cold deployment, installing an app on a server for the 1st time, we manually create the Application Pool & Virtual Directory in IIS.

  • Link for more info?

  • mendicant

    When we deploy, we have a set of nant tasks that gets run that does a similar set of steps to what you’ve done above….

    Short story, we remove the site and then recreate it pointing to new binaries, all within NAnt.

    I can see how deploying to dev would be really nice with this though. Have MSDeploy copy over our sql migration, and run it (nant). Then copy over our Web migration and run it (also nant).

  • Nice. If nothing else I like the file syncing aspect, and the ability to circumvent virus scanner rules (I’ve been burned by them multiple times; remotely copying EXEs to a computer is a no-no apparently)

  • @eddie, we currently use this for Hot deployments. I am looking at DropKick as a way for handling Cold deployments. see

    @rob .. you can find MSDeploy in the Web Deployment tool from here

    @mendicant we use a seperate nant script for deployements that is really light and kept seperate from our build scripts. so part of our deployment package does include the nant binaries… i am looking to get away from this and use DropKick instead..

    @peter I have exes in my sync, but I am using the Service and not IIS as the end point on the servers. I have made this work with nant deployments, msi, and exes.

  • mendicant

    Eric, we do the exact same thing. Packaged deployment script + Nant binaries.

  • msdeploy_dev

    If performing this step seems like a hassle:

    >> We do have to install MSDeploy on each server

    Try adding ,tempagent=true after computername=${deploy.server} in your command-line.

    Hope that helps!

  • Junk

    Fix your spelling errors…