<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Code Smart Not Hard - Team Deploy</title>
    <link>http://codesmartnothard.com/</link>
    <description>Team Foundation Server, Frameworks, and Code Generation</description>
    <language>en-us</language>
    <copyright>Michael Douglas</copyright>
    <lastBuildDate>Sat, 26 Sep 2009 18:16:00 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 1.9.6264.0</generator>
    <managingEditor>mike@doitconsultants.com</managingEditor>
    <webMaster>mike@doitconsultants.com</webMaster>
    <item>
      <trackback:ping>http://codesmartnothard.com/Trackback.aspx?guid=14e33dfd-20a1-4f39-bce2-43117e3bc779</trackback:ping>
      <pingback:server>http://codesmartnothard.com/pingback.aspx</pingback:server>
      <pingback:target>http://codesmartnothard.com/PermaLink,guid,14e33dfd-20a1-4f39-bce2-43117e3bc779.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://codesmartnothard.com/CommentView,guid,14e33dfd-20a1-4f39-bce2-43117e3bc779.aspx</wfw:comment>
      <wfw:commentRss>http://codesmartnothard.com/SyndicationService.asmx/GetEntryCommentsRss?guid=14e33dfd-20a1-4f39-bce2-43117e3bc779</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In <a href="http://codesmartnothard.com/ct.ashx?id=3d0434dc-2673-4c21-a186-f1f1ed281164&amp;url=http%3a%2f%2fcodesmartnothard.com%2fPermaLink%2cguid%2cf7709611-30b9-42d4-9474-e67cb6bc75b1.aspx">Part
1: The Deployment Process Should Enforce Good Configuration Management Practices</a>,
I gave some background on my experiences and how the configuration management process
has evolved and some rules and benefits to the automated deployment MSIs.
</p>
        <p>
In <a href="http://codesmartnothard.com/PermaLink,guid,3d0434dc-2673-4c21-a186-f1f1ed281164.aspx" target="_blank">Part
2: How to create an automated deployment MSI</a>, I walked through the steps to create
an automated deployment MSI in Visual Studio satisfying the rules from Part 1.
</p>
        <p>
In Part 3, I am going to walk through the steps to install Team Deploy.  Then
walk through creating a team build, configure Team Deploy, and deploy a MSI with it.  
</p>
        <p>
There is also a great <a href="http://www.noblegroupinternational.com/content/alm/teamdeploy/TeamDeploy.html" target="_blank">Screencast
by Ian Ceicys</a> walking through the entire process of installing TFS, WIX, Team
Deploy and deploying a MSI.  I highly recommend watching this.
</p>
        <h3>Installing PS Tools
</h3>
        <ul>
          <li>
Team Deploy uses the free PSExec and PSKill utilities by Sysinternals (owned by Microsoft). 
PSExec allows you to remotely run any command and PSKill can kill any process on a
local or remote machine.</li>
          <li>
Download PSTools at <a title="http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx" href="http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx">http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx</a> and
install to a local folder.  I also recommend renaming psexec and pskill to something
like psexec2.exe.  Some anti-virus software sees these files as a risk.</li>
        </ul>
        <p>
 
</p>
        <h3>Installing Team Deploy
</h3>
        <ul>
          <li>
Browse to the Team Deploy website on CodePlex at <a href="http://TeamDeploy.CodePlex.com">http://TeamDeploy.CodePlex.com</a></li>
          <li>
Click on the Downloads and download the TeamDeploy.MSI.</li>
          <li>
Run the MSI to install Team Deploy to c:\Program Files\MSBuild\TeamDeploy</li>
          <li>
The windows service account that runs Team Build on the build server will need to
be a local administrator on all target machines.</li>
        </ul>
        <h3> 
</h3>
        <h3>Creating a Team Deploy TFS Build
</h3>
        <ul>
          <li>
In Team Explorer, create a new build in your Team Project by right clicking on Builds
and choosing “New Build Definition”</li>
        </ul>
        <p>
          <img title="New Build Definition" alt="New Build Definition" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;DownloadId=80206" />
        </p>
        <p>
 
</p>
        <ul>
          <li>
Give it a name such as “Build and Deploy”</li>
        </ul>
        <ul>
          <li>
Create a workspace (Cloak other folders in your project that don’t need to be part
of the build. This helps the speed up your build because otherwise the server will
try to get all source files in the project)</li>
        </ul>
        <ul>
          <li>
Leave Project File name as is but click on the “Create” button to create a new TFSBuild.proj
file. 
</li>
        </ul>
        <ul>
          <li>
Next choose the solution you want to build, then the configuration type. I recommend
leaving the default. 
</li>
        </ul>
        <ul>
          <li>
Choose any options that you want to enable for running tests and/or code analysis.
I would recommend leaving these unchecked for now and once you verify everything is
working then go back and enable the options you want.</li>
        </ul>
        <ul>
          <li>
In TFS 2008, you can choose retention policies. This will help prevent builds from
filling up your server disk space quickly. I usually choose Keep 7 latest.</li>
        </ul>
        <ul>
          <li>
the next options are for the Build Defaults. Choose the appropriate build agent. If
unsure, just leave the default. Then choose the share where you want to copy the staging
files.</li>
        </ul>
        <ul>
          <li>
The last option is “Trigger”. The "build and deploy" build should be separate
from the continuous integration build. I recommend leaving the default “Check-ins
do not trigger a new build”.</li>
        </ul>
        <p>
 
</p>
        <p>
          <img title="Build Trigger" alt="Build Trigger" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;DownloadId=80218" />
        </p>
        <p>
 
</p>
        <ul>
          <li>
Finally click “OK” to create the build type.</li>
        </ul>
        <br />
Creating the build definition will create the TFSBuild.proj that contains the basic
options that were selected in the wizard. The following steps will customize the TFSBuild.proj
file created. This file is a Xml file based on MSBuild. 
<ul><li>
To modify the TFSBuild.proj file, located the file under Source Control -&gt; $/YourTeamProject/TeamBuildTypes/Build
and Deploy (You can also navigate directly to this file by right clicking on the build
definition and choosing "View Configuration Folder".)</li></ul><ul><li>
Check out and open the TFSBuild.proj file to configure it to use Team Deploy</li></ul><ul><li>
Find the comment &lt;!—Do not edit this -&gt; and add the following line underneath
the one that is already there. It should look something like the screenshot below</li></ul><blockquote><p>
&lt;Import Project="$(MSBuildExtensionsPath)\TeamDeploy\TeamDeploy.Tasks.targets"
/&gt;
</p></blockquote><p><img title="AddTeamDeployProject.jpg" alt="AddTeamDeployProject.jpg" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;DownloadId=80222" /></p><p>
 
</p><p>
Scroll to the bottom of the TFSBuild.proj file to the &lt;PropertyGroup&gt;. Overwrite
the Property group with the following (Adjust the paths for your specific environment):
</p><blockquote><p>
&lt;PropertyGroup&gt; 
<br />
    &lt;KillAppPathFilename&gt;c:\Program Files\PSTools\pskill2.exe&lt;/KillAppPathFilename&gt; 
<br />
    &lt;RemoteExecutePathFilename&gt;c:\Program Files\PStools\psexec2.exe&lt;/RemoteExecutePathFilename&gt; 
<br />
  &lt;/PropertyGroup&gt; 
</p><p>
  &lt;!-- Deploy MSI  --&gt; 
<br />
  &lt;Target Name="AfterEndToEndIteration"&gt; 
<br />
    &lt;CallTarget Condition="'$(IsDesktopBuild)'!='true'"
Targets="DeployMSITargetVirtuals" /&gt; 
<br />
  &lt;/Target&gt; 
</p><p>
  &lt;Target Name="DeployMSITargetVirtuals"&gt; 
<br />
    &lt;Deploy DeployScript="$(SolutionRoot)\..\..\Push Scripts\SampleDeploy.xml" 
<br />
            KillAppPathFilename="$(KillAppPathFilename)" 
<br />
            RemoteExecutePathFilename="$(RemoteExecutePathFilename)" 
<br />
            TeamFoundationServerUrl="$(TeamFoundationServerUrl)" 
<br />
            BuildUri="$(BuildUri)"
/&gt; 
<br />
  &lt;/Target&gt;
</p></blockquote><p>
The copied Xml in the TFSBuild.proj should look something like this
</p><p><img title="FinishedTFSBuild.jpg" alt="FinishedTFSBuild.jpg" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;DownloadId=80225" /></p><ul><li>
Save and check-in the TFSBuild.proj file</li></ul><p><br />
The Deploy task uses a Xml Deploy Script that contains the information of what Msi(s)
to deploy, additional tasks such as starting and stopping the service, and specifies
the target machines. The following steps walks you through editing this file.
</p><p><img title="DeployScript.jpg" alt="DeployScript.jpg" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;DownloadId=80227" /></p><p>
 
</p><p>
There are a few things to note here. 
</p><ul><li>
Team Deploy can 
<ul><li>
Kill 0 to many processes 
</li><li>
Deploy/Uninstall 0 to many MSIs 
</li><li>
Deploy MSIs to 0 to many Target Machines</li></ul></li></ul><ul><li>
Modify the xml appropriately for your environment. The GUID for the uninstalls are
the MSI product codes. If the MSI is done correctly it will uninstall previous versions
using the upgrade code, however they are usually unable to remove the same version
of the MSI, this is why we have the separate step of uninstall. 
</li></ul><ul><li>
The ExtraArgs element contains the SETUPENV variable that is used by the MSI’s custom
action to copy the correct environment’s config file to the project’s. The custom
action is a simple VBScript that copies the config file (not included with Team Deploy).
See Part 2 for more details on creating the config files folder structure.</li></ul><p>
 
</p><p>
Once the TFSBuild.proj is checked in and the Deploy script is saved (or also checked
in), then you can right click on the build and do a queue new build.   The
MSI will be deployed to your target machine(s). 
</p><p>
See the <a href="http://teamdeploy.codeplex.com/Wiki/View.aspx?title=Troubleshooting" target="_blank">Troubleshooting
/ FAQ section</a> of Team Deploy or contact me if you have any questions or problems.
</p><img width="0" height="0" src="http://codesmartnothard.com/aggbug.ashx?id=14e33dfd-20a1-4f39-bce2-43117e3bc779" /></body>
      <title>Deployments with TFS Part 3: Deploying MSIs to PCs and Servers</title>
      <guid isPermaLink="false">http://codesmartnothard.com/PermaLink,guid,14e33dfd-20a1-4f39-bce2-43117e3bc779.aspx</guid>
      <link>http://codesmartnothard.com/DeploymentsWithTFSPart3DeployingMSIsToPCsAndServers.aspx</link>
      <pubDate>Sat, 26 Sep 2009 18:16:00 GMT</pubDate>
      <description>&lt;p&gt;
In &lt;a href="http://codesmartnothard.com/ct.ashx?id=3d0434dc-2673-4c21-a186-f1f1ed281164&amp;amp;url=http%3a%2f%2fcodesmartnothard.com%2fPermaLink%2cguid%2cf7709611-30b9-42d4-9474-e67cb6bc75b1.aspx"&gt;Part
1: The Deployment Process Should Enforce Good Configuration Management Practices&lt;/a&gt;,
I gave some background on my experiences and how the configuration management process
has evolved and some rules and benefits to the automated deployment MSIs.
&lt;/p&gt;
&lt;p&gt;
In &lt;a href="http://codesmartnothard.com/PermaLink,guid,3d0434dc-2673-4c21-a186-f1f1ed281164.aspx" target="_blank"&gt;Part
2: How to create an automated deployment MSI&lt;/a&gt;, I walked through the steps to create
an automated deployment MSI in Visual Studio satisfying the rules from Part 1.
&lt;/p&gt;
&lt;p&gt;
In Part 3, I am going to walk through the steps to install Team Deploy.&amp;#160; Then
walk through creating a team build, configure Team Deploy, and deploy a MSI with it.&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
There is also a great &lt;a href="http://www.noblegroupinternational.com/content/alm/teamdeploy/TeamDeploy.html" target="_blank"&gt;Screencast
by Ian Ceicys&lt;/a&gt; walking through the entire process of installing TFS, WIX, Team
Deploy and deploying a MSI.&amp;#160; I highly recommend watching this.
&lt;/p&gt;
&lt;h3&gt;Installing PS Tools
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
Team Deploy uses the free PSExec and PSKill utilities by Sysinternals (owned by Microsoft).&amp;#160;
PSExec allows you to remotely run any command and PSKill can kill any process on a
local or remote machine.&lt;/li&gt;
&lt;li&gt;
Download PSTools at &lt;a title="http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx" href="http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx"&gt;http://technet.microsoft.com/en-us/sysinternals/bb896649.aspx&lt;/a&gt; and
install to a local folder.&amp;#160; I also recommend renaming psexec and pskill to something
like psexec2.exe.&amp;#160; Some anti-virus software sees these files as a risk.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;h3&gt;Installing Team Deploy
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
Browse to the Team Deploy website on CodePlex at &lt;a href="http://TeamDeploy.CodePlex.com"&gt;http://TeamDeploy.CodePlex.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
Click on the Downloads and download the TeamDeploy.MSI.&lt;/li&gt;
&lt;li&gt;
Run the MSI to install Team Deploy to c:\Program Files\MSBuild\TeamDeploy&lt;/li&gt;
&lt;li&gt;
The windows service account that runs Team Build on the build server will need to
be a local administrator on all target machines.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&amp;#160;
&lt;/h3&gt;
&lt;h3&gt;Creating a Team Deploy TFS Build
&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
In Team Explorer, create a new build in your Team Project by right clicking on Builds
and choosing “New Build Definition”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;img title="New Build Definition" alt="New Build Definition" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;amp;DownloadId=80206" /&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Give it a name such as “Build and Deploy”&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Create a workspace (Cloak other folders in your project that don’t need to be part
of the build. This helps the speed up your build because otherwise the server will
try to get all source files in the project)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Leave Project File name as is but click on the “Create” button to create a new TFSBuild.proj
file. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Next choose the solution you want to build, then the configuration type. I recommend
leaving the default. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Choose any options that you want to enable for running tests and/or code analysis.
I would recommend leaving these unchecked for now and once you verify everything is
working then go back and enable the options you want.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
In TFS 2008, you can choose retention policies. This will help prevent builds from
filling up your server disk space quickly. I usually choose Keep 7 latest.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
the next options are for the Build Defaults. Choose the appropriate build agent. If
unsure, just leave the default. Then choose the share where you want to copy the staging
files.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
The last option is “Trigger”. The &amp;quot;build and deploy&amp;quot; build should be separate
from the continuous integration build. I recommend leaving the default “Check-ins
do not trigger a new build”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
&lt;img title="Build Trigger" alt="Build Trigger" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;amp;DownloadId=80218" /&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Finally click “OK” to create the build type.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Creating the build definition will create the TFSBuild.proj that contains the basic
options that were selected in the wizard. The following steps will customize the TFSBuild.proj
file created. This file is a Xml file based on MSBuild. 
&lt;ul&gt;
&lt;li&gt;
To modify the TFSBuild.proj file, located the file under Source Control -&amp;gt; $/YourTeamProject/TeamBuildTypes/Build
and Deploy (You can also navigate directly to this file by right clicking on the build
definition and choosing &amp;quot;View Configuration Folder&amp;quot;.)&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Check out and open the TFSBuild.proj file to configure it to use Team Deploy&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Find the comment &amp;lt;!—Do not edit this -&amp;gt; and add the following line underneath
the one that is already there. It should look something like the screenshot below&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&amp;lt;Import Project=&amp;quot;$(MSBuildExtensionsPath)\TeamDeploy\TeamDeploy.Tasks.targets&amp;quot;
/&amp;gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
&lt;img title="AddTeamDeployProject.jpg" alt="AddTeamDeployProject.jpg" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;amp;DownloadId=80222" /&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
Scroll to the bottom of the TFSBuild.proj file to the &amp;lt;PropertyGroup&amp;gt;. Overwrite
the Property group with the following (Adjust the paths for your specific environment):
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&amp;lt;PropertyGroup&amp;gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;KillAppPathFilename&amp;gt;c:\Program Files\PSTools\pskill2.exe&amp;lt;/KillAppPathFilename&amp;gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;RemoteExecutePathFilename&amp;gt;c:\Program Files\PStools\psexec2.exe&amp;lt;/RemoteExecutePathFilename&amp;gt; 
&lt;br /&gt;
&amp;#160; &amp;lt;/PropertyGroup&amp;gt; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160; &amp;lt;!-- Deploy MSI&amp;#160; --&amp;gt; 
&lt;br /&gt;
&amp;#160; &amp;lt;Target Name=&amp;quot;AfterEndToEndIteration&amp;quot;&amp;gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;CallTarget Condition=&amp;quot;'$(IsDesktopBuild)'!='true'&amp;quot;
Targets=&amp;quot;DeployMSITargetVirtuals&amp;quot; /&amp;gt; 
&lt;br /&gt;
&amp;#160; &amp;lt;/Target&amp;gt; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160; &amp;lt;Target Name=&amp;quot;DeployMSITargetVirtuals&amp;quot;&amp;gt; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; &amp;lt;Deploy DeployScript=&amp;quot;$(SolutionRoot)\..\..\Push Scripts\SampleDeploy.xml&amp;quot; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; KillAppPathFilename=&amp;quot;$(KillAppPathFilename)&amp;quot; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; RemoteExecutePathFilename=&amp;quot;$(RemoteExecutePathFilename)&amp;quot; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; TeamFoundationServerUrl=&amp;quot;$(TeamFoundationServerUrl)&amp;quot; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; BuildUri=&amp;quot;$(BuildUri)&amp;quot;
/&amp;gt; 
&lt;br /&gt;
&amp;#160; &amp;lt;/Target&amp;gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The copied Xml in the TFSBuild.proj should look something like this
&lt;/p&gt;
&lt;p&gt;
&lt;img title="FinishedTFSBuild.jpg" alt="FinishedTFSBuild.jpg" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;amp;DownloadId=80225" /&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Save and check-in the TFSBuild.proj file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&lt;br /&gt;
The Deploy task uses a Xml Deploy Script that contains the information of what Msi(s)
to deploy, additional tasks such as starting and stopping the service, and specifies
the target machines. The following steps walks you through editing this file.
&lt;/p&gt;
&lt;p&gt;
&lt;img title="DeployScript.jpg" alt="DeployScript.jpg" src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=teamdeploy&amp;amp;DownloadId=80227" /&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
There are a few things to note here. 
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Team Deploy can 
&lt;ul&gt;
&lt;li&gt;
Kill 0 to many processes 
&lt;/li&gt;
&lt;li&gt;
Deploy/Uninstall 0 to many MSIs 
&lt;/li&gt;
&lt;li&gt;
Deploy MSIs to 0 to many Target Machines&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
Modify the xml appropriately for your environment. The GUID for the uninstalls are
the MSI product codes. If the MSI is done correctly it will uninstall previous versions
using the upgrade code, however they are usually unable to remove the same version
of the MSI, this is why we have the separate step of uninstall. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
The ExtraArgs element contains the SETUPENV variable that is used by the MSI’s custom
action to copy the correct environment’s config file to the project’s. The custom
action is a simple VBScript that copies the config file (not included with Team Deploy).
See Part 2 for more details on creating the config files folder structure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
Once the TFSBuild.proj is checked in and the Deploy script is saved (or also checked
in), then you can right click on the build and do a queue new build.&amp;#160;&amp;#160; The
MSI will be deployed to your target machine(s). 
&lt;/p&gt;
&lt;p&gt;
See the &lt;a href="http://teamdeploy.codeplex.com/Wiki/View.aspx?title=Troubleshooting" target="_blank"&gt;Troubleshooting
/ FAQ section&lt;/a&gt; of Team Deploy or contact me if you have any questions or problems.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://codesmartnothard.com/aggbug.ashx?id=14e33dfd-20a1-4f39-bce2-43117e3bc779" /&gt;</description>
      <comments>http://codesmartnothard.com/CommentView,guid,14e33dfd-20a1-4f39-bce2-43117e3bc779.aspx</comments>
      <category>Team Build;Team Deploy;Team Foundation Server</category>
    </item>
    <item>
      <trackback:ping>http://codesmartnothard.com/Trackback.aspx?guid=8794c8dc-e949-4b43-8bc7-22fffcc74e73</trackback:ping>
      <pingback:server>http://codesmartnothard.com/pingback.aspx</pingback:server>
      <pingback:target>http://codesmartnothard.com/PermaLink,guid,8794c8dc-e949-4b43-8bc7-22fffcc74e73.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://codesmartnothard.com/CommentView,guid,8794c8dc-e949-4b43-8bc7-22fffcc74e73.aspx</wfw:comment>
      <wfw:commentRss>http://codesmartnothard.com/SyndicationService.asmx/GetEntryCommentsRss?guid=8794c8dc-e949-4b43-8bc7-22fffcc74e73</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <a href="http://teamdeploy.codeplex.com/" target="_blank">Team Deploy</a> is a free
set of custom Team Build tasks for deploying MSIs to client PCs and servers. 
Team Deploy 2.1 has been released and includes a number of fixes and a couple new
features. 
<br /></p>
        <p>
A special thanks to Jeremy Novak for creating the new CleanupPsExec task and multiple
other fixes.  Here is the list of the changes:
</p>
        <ul>
          <li>
Moved Guidance and Installation from Word document to wiki site (and created a Troubleshooting
section) 
</li>
          <li>
Added -accepteula to all pstools calls so it won’t display the EULA dialog the first
time it runs</li>
          <li>
Added new CleanupPsExec task and test to <a href="http://teamdeploy.codeplex.com/Wiki/View.aspx?title=PSExecLocksUp&amp;referringTitle=Home" target="_blank">clean
up the PSTools service</a> if it becomes stuck. 
</li>
          <li>
Fixed spelling error in RemoteExecute task 
</li>
          <li>
Added support to uninstalling 32bit apps on Windows 2008 64bit servers 
</li>
          <li>
Changed property declarations to be auto-implemented 
</li>
          <li>
Updated task required properties to have the Required attribute 
</li>
          <li>
Created Team Deploy Installation Screencast 
</li>
          <li>
Other misc fixes. 
</li>
        </ul>
        <p>
Team Deploy 2.1 can be found on CodePlex at <a title="http://teamdeploy.codeplex.com/" href="http://teamdeploy.codeplex.com/">http://teamdeploy.codeplex.com/</a>.
</p>
        <p>
-Mike
</p>
        <img width="0" height="0" src="http://codesmartnothard.com/aggbug.ashx?id=8794c8dc-e949-4b43-8bc7-22fffcc74e73" />
      </body>
      <title>Team Deploy 2.1 Released</title>
      <guid isPermaLink="false">http://codesmartnothard.com/PermaLink,guid,8794c8dc-e949-4b43-8bc7-22fffcc74e73.aspx</guid>
      <link>http://codesmartnothard.com/TeamDeploy21Released.aspx</link>
      <pubDate>Wed, 26 Aug 2009 07:49:00 GMT</pubDate>
      <description>&lt;p&gt;
&lt;a href="http://teamdeploy.codeplex.com/" target="_blank"&gt;Team Deploy&lt;/a&gt; is a free
set of custom Team Build tasks for deploying MSIs to client PCs and servers.&amp;#160;
Team Deploy 2.1 has been released and includes a number of fixes and a couple new
features. 
&lt;br /&gt;
&lt;/p&gt;
&lt;p&gt;
A special thanks to Jeremy Novak for creating the new CleanupPsExec task and multiple
other fixes.&amp;#160; Here is the list of the changes:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
Moved Guidance and Installation from Word document to wiki site (and created a Troubleshooting
section) 
&lt;/li&gt;
&lt;li&gt;
Added -accepteula to all pstools calls so it won’t display the EULA dialog the first
time it runs&lt;/li&gt;
&lt;li&gt;
Added new CleanupPsExec task and test to &lt;a href="http://teamdeploy.codeplex.com/Wiki/View.aspx?title=PSExecLocksUp&amp;amp;referringTitle=Home" target="_blank"&gt;clean
up the PSTools service&lt;/a&gt; if it becomes stuck. 
&lt;/li&gt;
&lt;li&gt;
Fixed spelling error in RemoteExecute task 
&lt;/li&gt;
&lt;li&gt;
Added support to uninstalling 32bit apps on Windows 2008 64bit servers 
&lt;/li&gt;
&lt;li&gt;
Changed property declarations to be auto-implemented 
&lt;/li&gt;
&lt;li&gt;
Updated task required properties to have the Required attribute 
&lt;/li&gt;
&lt;li&gt;
Created Team Deploy Installation Screencast 
&lt;/li&gt;
&lt;li&gt;
Other misc fixes. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
Team Deploy 2.1 can be found on CodePlex at &lt;a title="http://teamdeploy.codeplex.com/" href="http://teamdeploy.codeplex.com/"&gt;http://teamdeploy.codeplex.com/&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
-Mike
&lt;/p&gt;
&lt;img width="0" height="0" src="http://codesmartnothard.com/aggbug.ashx?id=8794c8dc-e949-4b43-8bc7-22fffcc74e73" /&gt;</description>
      <comments>http://codesmartnothard.com/CommentView,guid,8794c8dc-e949-4b43-8bc7-22fffcc74e73.aspx</comments>
      <category>Team Build;Team Deploy;Team Foundation Server</category>
    </item>
    <item>
      <trackback:ping>http://codesmartnothard.com/Trackback.aspx?guid=3d0434dc-2673-4c21-a186-f1f1ed281164</trackback:ping>
      <pingback:server>http://codesmartnothard.com/pingback.aspx</pingback:server>
      <pingback:target>http://codesmartnothard.com/PermaLink,guid,3d0434dc-2673-4c21-a186-f1f1ed281164.aspx</pingback:target>
      <dc:creator>Your DisplayName here!</dc:creator>
      <wfw:comment>http://codesmartnothard.com/CommentView,guid,3d0434dc-2673-4c21-a186-f1f1ed281164.aspx</wfw:comment>
      <wfw:commentRss>http://codesmartnothard.com/SyndicationService.asmx/GetEntryCommentsRss?guid=3d0434dc-2673-4c21-a186-f1f1ed281164</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Note:  I slightly changed the title from TFS Deployments to Deployments with
TFS in case there was any confusion about whether this is about deploying TFS or doing
deployments with TFS.
</p>
        <p>
In <a href="http://codesmartnothard.com/PermaLink,guid,f7709611-30b9-42d4-9474-e67cb6bc75b1.aspx" target="_blank">Part
1: The Deployment Process Should Enforce Good Configuration Management Practices</a>,
I gave some background on my experiences and how the configuration management process
has evolved and some rules and benefits to the automated deployment MSIs.
</p>
        <p>
In this Part, I will walk through the steps to create an automated deployment MSI
in Visual Studio 2008 satisfying the rules from Part 1.    In this
example I will build the MSI for a windows service that will auto assign the username
and password.
</p>
        <p>
The first few steps are standard steps for building the MSI.  Then the steps
get more interesting when it starts getting into to the automated deployment settings.
</p>
        <h3>Step 1:  Add the Setup Project to existing solution
</h3>
        <p>
To add the setup project to the solution, choose “Add New Project” &gt; Other Project
Types &gt; Setup Project.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_2.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb.png" width="354" height="230" />
          </a>
        </p>
        <p>
 
</p>
        <h3>Step 2:  Add Project Output to MSI
</h3>
        <p>
Add the required files for the deployment by adding the project output of the primary
project.  To the project output, right click on the setup project in the solution
explorer  &gt; View &gt; Project Output.  A dialog box similar to the one
below will appear.  Verify that the windows service project is the selected project
in the combo box.  Choose Primary Output and click OK.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_4.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_1.png" width="208" height="244" />
          </a>
        </p>
        <p>
 
</p>
        <h3>Step 3:  Add Custom Actions
</h3>
        <p>
Next add the Primary output as a Custom action for the install, uninstall, etc. 
To do this, right click on the Custom Actions &gt; Add Custom Action &gt; Application
Folder &gt; Primary Output from &lt;your project&gt;.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_6.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_2.png" width="226" height="98" />
          </a>
        </p>
        <h3>Step 4:  Add Installer to Windows Service project
</h3>
        <p>
In the Windows Service project, add an Installer class by double clicking on the Service
component to view the designer.  In the Properties window (usually) at bottom
right corner, there will be a link to “Add Installer” similar to the image below. 
This creates the project installer class containing the service installer and the
process installer.  We will be modifying these in some later steps.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_8.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_3.png" width="304" height="244" />
          </a>
        </p>
        <h3>Step 5:  Create the environment config files and folders in the windows service
and add them to the MSI.
</h3>
        <p>
If the solution had multiple projects, I usually create a separate project for the
config files.  Here I will create the folders in the same project. Create the
folders and files as shown below.  Basically environment’s config file will be
stored here and checked into source control.  To add these to the MSI, go to
the properties of each config file and change the Build Action to Content.  Now
go back to the MSI, right click on the project &gt; Add &gt; Project Output &gt; Content
Files to add these.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_10.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_4.png" width="264" height="172" />
          </a>
        </p>
        <h3>Step 6:  Create Custom Action to copy the selected config file to the application
folder
</h3>
        <p>
Now that environment configs are in the ConfigFiles folder, the selected one needs
to be copied to Application folder.  To do this we need to create a custom action. 
This is in VBScript but eventually I want to create these custom actions as a helper
class in Team Deploy.  To create the custom task, the actual file needs to be
created outside the MSI.  I have created a CustomActions folder in the windows
service project.   In there I added a copyconfig.vbs file.  This custom
action is going to need two values passed into it.  One is the environment and
the other is TargetDir.  I couldn’t figure out a way to get current folder inside
for the vbscript so I found it easier to just pass it in.  To pass in values
into the custom action the name/value pairs are passed into the CustomActionData property. 
Also since this is going to overwrite the current app.config files, exclude the app.config
by clicking on the Primary Output &gt; Exclude &gt; Add for *.config.
</p>
        <p>
Here is the code for the copyconfig.vbs file.  After you copy and paste this
into the vbs file.  Save it and in the properties, change the Build Action to
None.   We do not want this copied to the MSI output like the config files.  
</p>
        <blockquote>
          <p>
on error resume next 
<br />
dim paramsList 
<br />
paramsList = split(session.property("CustomActionData"), ",") 
<br />
dim param1 
<br />
dim param2 
</p>
          <p>
param1 = paramsList(0) 
<br />
param2 = paramsList(1) 
</p>
          <p>
dim filesys 
<br />
dim path 
</p>
          <p>
path = param2 &amp; "configfiles\" &amp; param1 &amp; "\" 
</p>
          <p>
dim strEvn, objFile, strLogFile 
</p>
          <p>
Set objShell = CreateObject("Wscript.Shell") 
<br />
strEnv = objShell.ExpandEnvironmentStrings("%temp%") 
<br />
strLogFile = strEnv &amp; "\MSIInstallLog.txt" 
<br />
Set objFSO = CreateObject("Scripting.FileSystemObject") 
<br />
Set objFile = objFSO.OpenTextFile(strLogFile, 8, True) 
</p>
          <p>
objFSO.CopyFile path &amp; "*.config", param2, true 
</p>
          <p>
if err.number &gt; 0 then 
<br />
    objFile.WriteLine Now &amp; "::CopyConfigs - " &amp;
param1 &amp; err.Description 
<br />
else 
<br />
    objFile.WriteLine Now &amp; "::CopyConfigs - Completed Successfully." 
<br />
end if 
</p>
          <p>
objFile.Close
</p>
          <p>
          </p>
        </blockquote>
        <p>
Now add the Custom Action to the MSI by right clicking on the project &gt; View &gt;
Custom Actions.  We only want this to run during the installation process, so
right click on Install &gt; Add Custom Action &gt; Application Folder &gt; Add File
&gt; Browse to Copyconfig.vbs and click OK.  Notice in the setup project that
the copyconfig.vbs has the no sign icon on it so it isn’t copied to the application
folder.
</p>
        <p>
Next we need to pass in the the values into the Custom Action.  Click on the
Copyconfig.vbs in the Custom Actions view.  In the properties window, set CustomActionData
= [ENV],[TARGETDIR].  
</p>
        <p>
Repeat the steps above for AssignService.vbs.   Set CustomActionData = [USR],[PWD],"SampleService"
</p>
        <blockquote>
          <p>
on error resume next 
</p>
          <p>
dim param 
</p>
          <p>
param = split(session.property("CustomActionData"), ",") 
</p>
          <p>
if len(param(0)) &gt; 0 then 
</p>
          <p>
    dim strEvn, objFile, strLogFile 
</p>
          <p>
    Set objShell = CreateObject("Wscript.Shell") 
<br />
    strEnv = objShell.ExpandEnvironmentStrings("%temp%") 
<br />
    strLogFile = strEnv &amp; "\MSIInstallLog.txt" 
<br />
    Set objFSO = CreateObject("Scripting.FileSystemObject") 
<br />
    Set objFile = objFSO.OpenTextFile(strLogFile, 8, True) 
<br />
    ' ------ SCRIPT CONFIGURATION ------ 
<br />
    strUser     = param(0) 
<br />
    strPassword = param(1)       
<br />
    strSvcName  = cstr(replace(param(2), chr(34), "")) 
<br />
    strComputer = "."     
<br />
    ' ------ END CONFIGURATION --------- 
<br />
    set objWMI = GetObject("winmgmts:\\" &amp; strComputer
&amp; "\root\cimv2") 
<br />
    set objService = objWMI.Get("Win32_Service.Name='" &amp;
strSvcName &amp; "'") 
<br />
    intRC = objService.Change(,,,,,,strUser,strPassword) 
<br />
    if intRC &gt; 0 then 
<br />
       objFile.WriteLine Now &amp; "::" &amp;
strSvcName &amp; " - " &amp; "Error setting service account: "
&amp; intRC 
<br />
    else 
<br />
       objFile.WriteLine Now &amp; "::" &amp;
strSvcName &amp; " - " &amp; "Successfully set service account" 
<br />
    end if 
<br />
    if err.number &gt; 0 then 
<br />
        objFile.WriteLine Now &amp; "::"
&amp; strSvcName &amp; " - " &amp; err.Description 
<br />
    end if 
<br />
    objFile.Close 
</p>
          <p>
end if
</p>
          <p>
          </p>
        </blockquote>
        <p>
This custom action finds the “SampleService” and changes the username and password. 
I had to use the service name literal.  There wasn’t anything I could find where
I could use a dynamic value.
</p>
        <h3>Step 7:  Modify Project Installer to handle interactive and silent modes
</h3>
        <p>
One of the requirements is that the MSI needs to work when using the wizard and when
specifying parameters when installing from the command line or remote utility. 
Therefore when the user is installing the MSI through the wizard (we will create this
in the next step)   it needs to prompt for the user and password. 
This is accomplished by setting the service account of the installer to LocalSystem
so it won’t prompt but if the username isn’t passed in it switches the service account
to User.  This will then prompt the user.
</p>
        <p>
To implement this, add the following code to the ProjectInstaller.
</p>
        <blockquote>
          <p>
private string GetContextParameter(string key) 
<br />
{ 
<br />
    string sValue = ""; 
</p>
          <p>
    try 
<br />
    { 
<br />
        sValue = this.Context.Parameters[key].ToString(); 
</p>
          <p>
    } 
<br />
    catch 
<br />
    { 
<br />
        sValue = ""; 
<br />
    } 
</p>
          <p>
    return sValue; 
<br />
}        
</p>
          <p>
// Override the 'OnBeforeInstall' method.        
<br />
protected override void OnBeforeInstall(IDictionary savedState) 
<br />
{ 
<br />
    try 
<br />
    { 
<br />
    base.OnBeforeInstall(savedState); 
<br />
    string username = GetContextParameter("usr").Trim(); 
</p>
          <p>
        if (username == "") 
<br />
        { 
<br />
            serviceProcessInstaller1.Account
= System.ServiceProcess.ServiceAccount.User; 
<br />
        } 
<br />
    } 
<br />
    catch(Exception e) 
<br />
    { 
</p>
          <p>
  } 
<br />
} 
</p>
          <p>
private string getvalues() 
<br />
{ 
<br />
    string all = ""; 
</p>
          <p>
    foreach (DictionaryEntry value in this.Context.Parameters) 
<br />
    { 
<br />
        all += value.Value.ToString() + ","; 
<br />
    } 
<br />
    return all; 
<br />
}
</p>
        </blockquote>
        <h3>Step 8:  Add step to wizard to specify the Environment.
</h3>
        <p>
In addition to prompting the user for the user and password, the MSI needs to prompt
the user for the environment.  To add a form to the Wizard.  Right click
on the setup project &gt; View &gt; User Interface.  Then right click on Start
(as shown) and the click Add Dialog.  In this example we have 3 environment,
so choose the RadioButtons (3 Buttons) and press Ok.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_12.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_5.png" width="244" height="161" />
          </a>
        </p>
        <p>
        </p>
        <p>
The Dialog window appears below the Confirm Installation box.  If you build the
setup project you will notice the warning, “All custom dialogs must precede the 'Installation
Folder' dialog”.  Therefore, click on the up arrow twice to move the RadioButton
dialog window  above the Installation folder.  Now click on the dialog and
view the Properties window.  There are several empty properties we need to set. 
Set the following to something similar to these values:
</p>
        <ul>
          <li>
BannerText = “Choose Environment” 
</li>
          <li>
BodyText = “Please select an environment from the list.” 
</li>
          <li>
Button1Label = “Production” 
</li>
          <li>
Button1Value = “Prod” 
</li>
          <li>
Button2Label = “Test” 
</li>
          <li>
Button2Value “Test” 
</li>
          <li>
Button3Labal = “Development” 
</li>
          <li>
Button3Value = “Dev” 
</li>
          <li>
ButtonProperty = “Env” 
</li>
          <li>
DefaultValue = “Prod” 
</li>
        </ul>
        <p>
 
</p>
        <h3>Step 9:  Change build type to loose uncompressed files
</h3>
        <p>
The last step is to change the Package Files option under the setup project’s properties
from “In setup file” to “As loose uncompressed files.  You will need to do this
for each configuration in the project.
</p>
        <p>
          <a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_14.png">
            <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_6.png" width="404" height="281" />
          </a>
        </p>
        <p>
 
</p>
        <p>
These are all of the steps.  I hope it helps.  Attached below is the sample
solution with the setup project hosted on the MSDN Code Gallery.  You may use
this however you would like.  Now that you know how to build the MSI, it is time
to deploy it.  I will walk through that in the next post.
</p>
        <p>
          <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=msi&amp;DownloadId=6714" target="_blank">Sample
Automated Deployment Solution for building a Windows Service MSI</a> (22k)
</p>
        <p>
The other future parts in the series will include:
</p>
        <ol>
          <li>
Building and Deploying ClickOnce applications</li>
          <li>
Deploying a web application.</li>
          <li>
Hopefully more!  Let me know what you would like to see.</li>
        </ol>
        <p>
 
</p>
        <p>
Mike
</p>
        <img width="0" height="0" src="http://codesmartnothard.com/aggbug.ashx?id=3d0434dc-2673-4c21-a186-f1f1ed281164" />
      </body>
      <title>Deployments with TFS Part 2: How to create an automated deployment MSI</title>
      <guid isPermaLink="false">http://codesmartnothard.com/PermaLink,guid,3d0434dc-2673-4c21-a186-f1f1ed281164.aspx</guid>
      <link>http://codesmartnothard.com/DeploymentsWithTFSPart2HowToCreateAnAutomatedDeploymentMSI.aspx</link>
      <pubDate>Thu, 30 Jul 2009 10:14:00 GMT</pubDate>
      <description>&lt;p&gt;
Note:&amp;#160; I slightly changed the title from TFS Deployments to Deployments with
TFS in case there was any confusion about whether this is about deploying TFS or doing
deployments with TFS.
&lt;/p&gt;
&lt;p&gt;
In &lt;a href="http://codesmartnothard.com/PermaLink,guid,f7709611-30b9-42d4-9474-e67cb6bc75b1.aspx" target="_blank"&gt;Part
1: The Deployment Process Should Enforce Good Configuration Management Practices&lt;/a&gt;,
I gave some background on my experiences and how the configuration management process
has evolved and some rules and benefits to the automated deployment MSIs.
&lt;/p&gt;
&lt;p&gt;
In this Part, I will walk through the steps to create an automated deployment MSI
in Visual Studio 2008 satisfying the rules from Part 1.&amp;#160;&amp;#160;&amp;#160; In this
example I will build the MSI for a windows service that will auto assign the username
and password.
&lt;/p&gt;
&lt;p&gt;
The first few steps are standard steps for building the MSI.&amp;#160; Then the steps
get more interesting when it starts getting into to the automated deployment settings.
&lt;/p&gt;
&lt;h3&gt;Step 1:&amp;#160; Add the Setup Project to existing solution
&lt;/h3&gt;
&lt;p&gt;
To add the setup project to the solution, choose “Add New Project” &amp;gt; Other Project
Types &amp;gt; Setup Project.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb.png" width="354" height="230" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;h3&gt;Step 2:&amp;#160; Add Project Output to MSI
&lt;/h3&gt;
&lt;p&gt;
Add the required files for the deployment by adding the project output of the primary
project.&amp;#160; To the project output, right click on the setup project in the solution
explorer&amp;#160; &amp;gt; View &amp;gt; Project Output.&amp;#160; A dialog box similar to the one
below will appear.&amp;#160; Verify that the windows service project is the selected project
in the combo box.&amp;#160; Choose Primary Output and click OK.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_1.png" width="208" height="244" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;h3&gt;Step 3:&amp;#160; Add Custom Actions
&lt;/h3&gt;
&lt;p&gt;
Next add the Primary output as a Custom action for the install, uninstall, etc.&amp;#160;
To do this, right click on the Custom Actions &amp;gt; Add Custom Action &amp;gt; Application
Folder &amp;gt; Primary Output from &amp;lt;your project&amp;gt;.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_2.png" width="226" height="98" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;h3&gt;Step 4:&amp;#160; Add Installer to Windows Service project
&lt;/h3&gt;
&lt;p&gt;
In the Windows Service project, add an Installer class by double clicking on the Service
component to view the designer.&amp;#160; In the Properties window (usually) at bottom
right corner, there will be a link to “Add Installer” similar to the image below.&amp;#160;
This creates the project installer class containing the service installer and the
process installer.&amp;#160; We will be modifying these in some later steps.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_8.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_3.png" width="304" height="244" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;h3&gt;Step 5:&amp;#160; Create the environment config files and folders in the windows service
and add them to the MSI.
&lt;/h3&gt;
&lt;p&gt;
If the solution had multiple projects, I usually create a separate project for the
config files.&amp;#160; Here I will create the folders in the same project. Create the
folders and files as shown below.&amp;#160; Basically environment’s config file will be
stored here and checked into source control.&amp;#160; To add these to the MSI, go to
the properties of each config file and change the Build Action to Content.&amp;#160; Now
go back to the MSI, right click on the project &amp;gt; Add &amp;gt; Project Output &amp;gt; Content
Files to add these.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_10.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_4.png" width="264" height="172" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;h3&gt;Step 6:&amp;#160; Create Custom Action to copy the selected config file to the application
folder
&lt;/h3&gt;
&lt;p&gt;
Now that environment configs are in the ConfigFiles folder, the selected one needs
to be copied to Application folder.&amp;#160; To do this we need to create a custom action.&amp;#160;
This is in VBScript but eventually I want to create these custom actions as a helper
class in Team Deploy.&amp;#160; To create the custom task, the actual file needs to be
created outside the MSI.&amp;#160; I have created a CustomActions folder in the windows
service project.&amp;#160;&amp;#160; In there I added a copyconfig.vbs file.&amp;#160; This custom
action is going to need two values passed into it.&amp;#160; One is the environment and
the other is TargetDir.&amp;#160; I couldn’t figure out a way to get current folder inside
for the vbscript so I found it easier to just pass it in.&amp;#160; To pass in values
into the custom action the name/value pairs are passed into the CustomActionData property.&amp;#160;
Also since this is going to overwrite the current app.config files, exclude the app.config
by clicking on the Primary Output &amp;gt; Exclude &amp;gt; Add for *.config.
&lt;/p&gt;
&lt;p&gt;
Here is the code for the copyconfig.vbs file.&amp;#160; After you copy and paste this
into the vbs file.&amp;#160; Save it and in the properties, change the Build Action to
None.&amp;#160;&amp;#160; We do not want this copied to the MSI output like the config files.&amp;#160; 
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
on error resume next 
&lt;br /&gt;
dim paramsList 
&lt;br /&gt;
paramsList = split(session.property(&amp;quot;CustomActionData&amp;quot;), &amp;quot;,&amp;quot;) 
&lt;br /&gt;
dim param1 
&lt;br /&gt;
dim param2 
&lt;/p&gt;
&lt;p&gt;
param1 = paramsList(0) 
&lt;br /&gt;
param2 = paramsList(1) 
&lt;/p&gt;
&lt;p&gt;
dim filesys 
&lt;br /&gt;
dim path 
&lt;/p&gt;
&lt;p&gt;
path = param2 &amp;amp; &amp;quot;configfiles\&amp;quot; &amp;amp; param1 &amp;amp; &amp;quot;\&amp;quot; 
&lt;/p&gt;
&lt;p&gt;
dim strEvn, objFile, strLogFile 
&lt;/p&gt;
&lt;p&gt;
Set objShell = CreateObject(&amp;quot;Wscript.Shell&amp;quot;) 
&lt;br /&gt;
strEnv = objShell.ExpandEnvironmentStrings(&amp;quot;%temp%&amp;quot;) 
&lt;br /&gt;
strLogFile = strEnv &amp;amp; &amp;quot;\MSIInstallLog.txt&amp;quot; 
&lt;br /&gt;
Set objFSO = CreateObject(&amp;quot;Scripting.FileSystemObject&amp;quot;) 
&lt;br /&gt;
Set objFile = objFSO.OpenTextFile(strLogFile, 8, True) 
&lt;/p&gt;
&lt;p&gt;
objFSO.CopyFile path &amp;amp; &amp;quot;*.config&amp;quot;, param2, true 
&lt;/p&gt;
&lt;p&gt;
if err.number &amp;gt; 0 then 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; objFile.WriteLine Now &amp;amp; &amp;quot;::CopyConfigs - &amp;quot; &amp;amp;
param1 &amp;amp; err.Description 
&lt;br /&gt;
else 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; objFile.WriteLine Now &amp;amp; &amp;quot;::CopyConfigs - Completed Successfully.&amp;quot; 
&lt;br /&gt;
end if 
&lt;/p&gt;
&lt;p&gt;
objFile.Close
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
Now add the Custom Action to the MSI by right clicking on the project &amp;gt; View &amp;gt;
Custom Actions.&amp;#160; We only want this to run during the installation process, so
right click on Install &amp;gt; Add Custom Action &amp;gt; Application Folder &amp;gt; Add File
&amp;gt; Browse to Copyconfig.vbs and click OK.&amp;#160; Notice in the setup project that
the copyconfig.vbs has the no sign icon on it so it isn’t copied to the application
folder.
&lt;/p&gt;
&lt;p&gt;
Next we need to pass in the the values into the Custom Action.&amp;#160; Click on the
Copyconfig.vbs in the Custom Actions view.&amp;#160; In the properties window, set CustomActionData
= [ENV],[TARGETDIR].&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
Repeat the steps above for AssignService.vbs.&amp;#160;&amp;#160; Set CustomActionData = [USR],[PWD],&amp;quot;SampleService&amp;quot;
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
on error resume next 
&lt;/p&gt;
&lt;p&gt;
dim param 
&lt;/p&gt;
&lt;p&gt;
param = split(session.property(&amp;quot;CustomActionData&amp;quot;), &amp;quot;,&amp;quot;) 
&lt;/p&gt;
&lt;p&gt;
if len(param(0)) &amp;gt; 0 then 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160; dim strEvn, objFile, strLogFile 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160; Set objShell = CreateObject(&amp;quot;Wscript.Shell&amp;quot;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; strEnv = objShell.ExpandEnvironmentStrings(&amp;quot;%temp%&amp;quot;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; strLogFile = strEnv &amp;amp; &amp;quot;\MSIInstallLog.txt&amp;quot; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; Set objFSO = CreateObject(&amp;quot;Scripting.FileSystemObject&amp;quot;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; Set objFile = objFSO.OpenTextFile(strLogFile, 8, True) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; ' ------ SCRIPT CONFIGURATION ------ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; strUser&amp;#160;&amp;#160;&amp;#160;&amp;#160; = param(0) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; strPassword = param(1)&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; strSvcName&amp;#160; = cstr(replace(param(2), chr(34), &amp;quot;&amp;quot;)) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; strComputer = &amp;quot;.&amp;quot;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; ' ------ END CONFIGURATION --------- 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; set objWMI = GetObject(&amp;quot;winmgmts:\\&amp;quot; &amp;amp; strComputer
&amp;amp; &amp;quot;\root\cimv2&amp;quot;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; set objService = objWMI.Get(&amp;quot;Win32_Service.Name='&amp;quot; &amp;amp;
strSvcName &amp;amp; &amp;quot;'&amp;quot;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; intRC = objService.Change(,,,,,,strUser,strPassword) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; if intRC &amp;gt; 0 then 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objFile.WriteLine Now &amp;amp; &amp;quot;::&amp;quot; &amp;amp;
strSvcName &amp;amp; &amp;quot; - &amp;quot; &amp;amp; &amp;quot;Error setting service account: &amp;quot;
&amp;amp; intRC 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; else 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objFile.WriteLine Now &amp;amp; &amp;quot;::&amp;quot; &amp;amp;
strSvcName &amp;amp; &amp;quot; - &amp;quot; &amp;amp; &amp;quot;Successfully set service account&amp;quot; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; end if 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; if err.number &amp;gt; 0 then 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; objFile.WriteLine Now &amp;amp; &amp;quot;::&amp;quot;
&amp;amp; strSvcName &amp;amp; &amp;quot; - &amp;quot; &amp;amp; err.Description 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; end if 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; objFile.Close 
&lt;/p&gt;
&lt;p&gt;
end if
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
This custom action finds the “SampleService” and changes the username and password.&amp;#160;
I had to use the service name literal.&amp;#160; There wasn’t anything I could find where
I could use a dynamic value.
&lt;/p&gt;
&lt;h3&gt;Step 7:&amp;#160; Modify Project Installer to handle interactive and silent modes
&lt;/h3&gt;
&lt;p&gt;
One of the requirements is that the MSI needs to work when using the wizard and when
specifying parameters when installing from the command line or remote utility.&amp;#160;
Therefore when the user is installing the MSI through the wizard (we will create this
in the next step)&amp;#160;&amp;#160; it needs to prompt for the user and password.&amp;#160;
This is accomplished by setting the service account of the installer to LocalSystem
so it won’t prompt but if the username isn’t passed in it switches the service account
to User.&amp;#160; This will then prompt the user.
&lt;/p&gt;
&lt;p&gt;
To implement this, add the following code to the ProjectInstaller.
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
private string GetContextParameter(string key) 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; string sValue = &amp;quot;&amp;quot;; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160; try 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; sValue = this.Context.Parameters[key].ToString(); 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; catch 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; sValue = &amp;quot;&amp;quot;; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160; return sValue; 
&lt;br /&gt;
}&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;/p&gt;
&lt;p&gt;
// Override the 'OnBeforeInstall' method.&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; 
&lt;br /&gt;
protected override void OnBeforeInstall(IDictionary savedState) 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; try 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; base.OnBeforeInstall(savedState); 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; string username = GetContextParameter(&amp;quot;usr&amp;quot;).Trim(); 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; if (username == &amp;quot;&amp;quot;) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; serviceProcessInstaller1.Account
= System.ServiceProcess.ServiceAccount.User; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; catch(Exception e) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;/p&gt;
&lt;p&gt;
&amp;#160; } 
&lt;br /&gt;
} 
&lt;/p&gt;
&lt;p&gt;
private string getvalues() 
&lt;br /&gt;
{ 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; string all = &amp;quot;&amp;quot;; 
&lt;/p&gt;
&lt;p&gt;
&amp;#160;&amp;#160;&amp;#160; foreach (DictionaryEntry value in this.Context.Parameters) 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; { 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; all += value.Value.ToString() + &amp;quot;,&amp;quot;; 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; } 
&lt;br /&gt;
&amp;#160;&amp;#160;&amp;#160; return all; 
&lt;br /&gt;
}
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;h3&gt;Step 8:&amp;#160; Add step to wizard to specify the Environment.
&lt;/h3&gt;
&lt;p&gt;
In addition to prompting the user for the user and password, the MSI needs to prompt
the user for the environment.&amp;#160; To add a form to the Wizard.&amp;#160; Right click
on the setup project &amp;gt; View &amp;gt; User Interface.&amp;#160; Then right click on Start
(as shown) and the click Add Dialog.&amp;#160; In this example we have 3 environment,
so choose the RadioButtons (3 Buttons) and press Ok.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_12.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_5.png" width="244" height="161" /&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;p&gt;
The Dialog window appears below the Confirm Installation box.&amp;#160; If you build the
setup project you will notice the warning, “All custom dialogs must precede the 'Installation
Folder' dialog”.&amp;#160; Therefore, click on the up arrow twice to move the RadioButton
dialog window&amp;#160; above the Installation folder.&amp;#160; Now click on the dialog and
view the Properties window.&amp;#160; There are several empty properties we need to set.&amp;#160;
Set the following to something similar to these values:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
BannerText = “Choose Environment” 
&lt;/li&gt;
&lt;li&gt;
BodyText = “Please select an environment from the list.” 
&lt;/li&gt;
&lt;li&gt;
Button1Label = “Production” 
&lt;/li&gt;
&lt;li&gt;
Button1Value = “Prod” 
&lt;/li&gt;
&lt;li&gt;
Button2Label = “Test” 
&lt;/li&gt;
&lt;li&gt;
Button2Value “Test” 
&lt;/li&gt;
&lt;li&gt;
Button3Labal = “Development” 
&lt;/li&gt;
&lt;li&gt;
Button3Value = “Dev” 
&lt;/li&gt;
&lt;li&gt;
ButtonProperty = “Env” 
&lt;/li&gt;
&lt;li&gt;
DefaultValue = “Prod” 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;h3&gt;Step 9:&amp;#160; Change build type to loose uncompressed files
&lt;/h3&gt;
&lt;p&gt;
The last step is to change the Package Files option under the setup project’s properties
from “In setup file” to “As loose uncompressed files.&amp;#160; You will need to do this
for each configuration in the project.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_14.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://codesmartnothard.com/content/binary/WindowsLiveWriter/DeploymentswithTFSPart2Howtocreateanauto_7459/image_thumb_6.png" width="404" height="281" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
These are all of the steps.&amp;#160; I hope it helps.&amp;#160; Attached below is the sample
solution with the setup project hosted on the MSDN Code Gallery.&amp;#160; You may use
this however you would like.&amp;#160; Now that you know how to build the MSI, it is time
to deploy it.&amp;#160; I will walk through that in the next post.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=msi&amp;amp;DownloadId=6714" target="_blank"&gt;Sample
Automated Deployment Solution for building a Windows Service MSI&lt;/a&gt; (22k)
&lt;/p&gt;
&lt;p&gt;
The other future parts in the series will include:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Building and Deploying ClickOnce applications&lt;/li&gt;
&lt;li&gt;
Deploying a web application.&lt;/li&gt;
&lt;li&gt;
Hopefully more!&amp;#160; Let me know what you would like to see.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
&amp;#160;
&lt;/p&gt;
&lt;p&gt;
Mike
&lt;/p&gt;
&lt;img width="0" height="0" src="http://codesmartnothard.com/aggbug.ashx?id=3d0434dc-2673-4c21-a186-f1f1ed281164" /&gt;</description>
      <comments>http://codesmartnothard.com/CommentView,guid,3d0434dc-2673-4c21-a186-f1f1ed281164.aspx</comments>
      <category>Team Build;Team Deploy;Team Foundation Server</category>
    </item>
  </channel>
</rss>