First, download msdeploy from here: http://www.iis.net/download/WebDeploy
Then install it like this:
msiexec /i <msi_filename> /passive ADDLOCAL=ALL LISTENURL=https://+:443/MsDeployAgentService/
(you can change the port and listen path if you like, if you do, be sure to use your different port in the next step below)
Then, get yourself an SSL or create a self signed one, in install it against MSDeploy like so:
Server 2003:
httpcfg set ssl -i 0.0.0.0:443 -h <cert hash> -g {00000000-0000-0000-0000-000000000000}
Server 2008:
netsh.exe http add sslcert ipport=0.0.0.0:443 appid={00000000-0000-0000-0000-000000000000} certhash=<cert hash>
To find your cert hash, either through IIS or the Certificates MMC snap-in view your cert, copy the thumbprint into notepad and remove the spaces.
Then, to connect to MSDeploy remotely, use the following command:
msdeploy.exe -verb:sync -source:dirPath='<Some Local Path>' -dest:dirPath='<Some Remote Path>',computername=<Remote server name>,userName=<Remote User>,password=<Password> -verbose
Add the -allowUntrusted switch if you are using a self signed SSL.
I’ve already got a bunch of lovely build scripts and remote management scripts that I won’t go into here, what I am going to talk about is how I’ve wired them together using MSDeploy to push my code to my remote server.
First off, install the Web Deployment Tool on your remote machine, but to help prevent haxing don’t put the remote agent service on the default URI. Instead I used a custom port and set up a firewall rule to only allow this port from our office’s IP address. Download the installer and run:
msiexec /I WebDeploy_x64_en-US.msi /passive ADDLOCAL=ALL LISTENURL=http://+:1234/MSDeploy/
N.B. you can change the port and path to whatever you like.
Here are the installation docs.
Next, goto Services and start “Web Deployment Agent Service”, or run:
net start msdepsvc
You probably also want to set it to Automatic instead of Manual. Then, set up your MSDeploy script to push your code:
c:\program files\iis\microsoft web deploy\msdeploy.exe -verb:sync
-source:dirPath='d:\some\local\path'
-dest:dirPath='f:\some\remote\path',computerName=http://xxx.xxx.xxx.xxx:1234/MSDeploy,
userName=remoteUser,password=remotePassword -verbose
N.B. “dirPath” is for pushing a whole directory, you can’t use this for a single file (I’m sure there’s a different switch for that though, see the docs, good luck.)
You can then execute a remote command:
c:\program files\iis\microsoft web deploy\msdeploy.exe -verb:sync
-source:runCommand='f:\some\remote\path\somefile.bat',waitInterval=15000,waitAttempts=1
-dest:auto',computerName=http://xxx.xxx.xxx.xxx:1234/MSDeploy,
userName=remoteUser,password=remotePassword -verbose
The docs say that “waitAttempts” is the number of subsequent retry attempts so initially set it to 0, but I found that any waitInterval causes a timeout unless I set “waitAttempts” to 1 (presumably anything >0). Crap, but it works.
Note that in this example runCommand will call:
"C:\Windows\System32\cmd.exe" /c "f:\some\remote\path\somefile.bat"
which means the current directory for the execution of the batch file is “C:\Windows\System32″. If you put:
cd /d %~dp0
in your batch file, it will change the working dir to the path where the batch file resides. 1337.
Here are some docs.
MSDemply runCommand docs
MSDeploy Command line docs
MSDeploy Command line docs part deux (the bit you actually need)
Recently I posted about how you can split your CSS up into separate files, and use a NAnt task to combine them on build to aid development.
This can be very useful, but theres still room for improvement.
The YUI Compressor is a brilliant tool to remove whitespace and other bloat from your scripts which take up valuable bandwidth. Combining it with an automated build tool such as NAnt allows you to have all your scripts minified automatically on deployment.
Here are two example build tasks for minifying JavaScript and CSS respectively:
<target name="compress-js">
<foreach item="File" property="filename">
<in>
<items basedir="output/build/assets/javascript/">
<include name="/**/*.js" />
<exclude name="/**/*.min.js" />
<exclude name="/**/*.pack.js" />
</items>
</in>
<do>
<exec basedir="." program="${JavaPath}java" commandline=" -jar ${YUICompressorPath}yuicompressor-2.4.1.jar --type js --charset utf-8 -o &quot;${filename}&quot; &quot;${filename}&quot;" failonerror="true" />
</do>
</foreach>
</target>
<target name="compress-css" depends="combine-css">
<foreach item="File" property="filename">
<in>
<items basedir="output/build/assets/css/">
<include name="/**/*.css" />
<exclude name="/**/*.min.css" />
<exclude name="/**/*.pack.css" />
</items>
</in>
<do>
<exec basedir="." program="${JavaPath}java" commandline=" -jar ${YUICompressorPath}yuicompressor-2.4.1.jar --type css --charset utf-8 -o &quot;${filename}&quot; &quot;${filename}&quot;" failonerror="true" />
</do>
</foreach>
</target>
Using this in combination with my CssCombiner, I achieve an average of 70% compression!
Enoy
One of the most difficult aspecs of web development today is managing and maintaining your stylesheets. Typically you have a single huge file, divided into sections by comment blocks (if you’re organised). Navigating to the group of styles you need to edit typically involves Ctrl-F and lots of inside knowledge. Individual CSS developers tend to have their own quirks when it comes to the internal organisation of their “monolith.css”. Some like to separate structure and layout from colour and style whilst others like to define all attributes for a selector in a single place. The result of all these different, typically unmanaged techniques can make it very difficult for maintenence developers to get to grips with legacy stylesheets, surely there must be a solution?
Take a look at this CSS from a recent project I worked on…

default.css contains:
@Import url(Reset.css);
@Import url(MainLayout.css);
@Import url(Components/Header.css);
@Import url(Components/Misc.css);
@Import url(Components/WhiteBox.css);
@Import url(Components/Forms.css);
@Import url(Components/BaseModal.css);
@Import url(Components/CustomModal.css);
@Import url(Components/Popup.css);
@Import url(Components/DefinitionList.css);
@Import url(Components/ResultMessage.css);
@Import url(Components/ShipmentCalendar.css);
@Import url(Components/Severity.css);
@Import url(Components/Document.css);
@Import url(Components/ResultsTable.css);
@Import url(Components/TaskList.css);
@Import url(Components/TodoList.css);
@Import url(Components/ContractList.css);
@Import url(Components/ShipmentList.css);
@Import url(Components/EditIcons.css);
@Import url(Components/UserList.css);
@Import url(Components/SimpleList.css);
@Import url(Components/ApplicationForm.css);
@Import url(Components/jquery.ui.css);
@Import url(Components/Blank.css);
@Import url(Components/thickbox.css);
Each file in the components folder contains just a few lines of related styles, on the topic of the filename.
The more astute among you may have realised however that whilst this mass of @Imports might be super useful for development, its going to create an HTTP request spamathon on each page request.
Step up my CSS combining NAnt task.
As an aside, I am currently migrating towards Rake instead of NAnt as my build tool, and when I do I shall create a Ruby version of this.
Point the task at your CSS files, and it will run over them, replacing each @Import directive with the CSS that would actually be imported. Awesome! This means you can divide your CSS up into a million, super granular files and not need to worry about any HTTP request overheads, because in the live environment, you will only have a single file
To use the task:
- Import the dll into your .build file
- Point the CssCombiner task at your built CSS files (NOT YOUR SOURCE CODE)
- Go and do something else with the time you have saved
Here is an example:
<loadtasks assembly="./tools/CssCombiner.NAntTask.dll" />
<target name="combine-css">
<CssCombiner>
<fileset basedir="output/build/">
<include name="/**/*.css" />
</fileset>
</CssCombiner>
</target>
Enjoy