Showing posts with label Wix. Show all posts
Showing posts with label Wix. Show all posts

Monday, 1 September 2014

Product Versions in MSI installers created with WIX - part 2

In a previous post I described how to change the version of MSI installers created with WiX.

This post discusses a way of linking the version number of an assembly (library, dll, executable) to the product version.

This is more suited to a library/framework, where you want to ensure that the product version is the same as the library/framework.
  1. On the library project, edit the AssemblyInfo.cs file:

  2. Remove these two lines:
    [assembly: AssemblyVersion("1.0.0.0")]
    [assembly: AssemblyFileVersion("1.0.0.0")]
  3. Create a new File called VersionInfo.cs on the Properties folder.

  4. Contents of file should be:
    [assembly: System.Reflection.AssemblyVersion("0.0.0.*")]
  5. Edit the project file (you'll need to unload the project if you want to do it from Visual Studio) and at the end, you'll find a commented out section. Get rid of it (everything between <!-- -->) and add the following:
  6. <Target Name="BeforeBuild"> < <WriteLinesToFile Condition=" '$(Version)' != '' " File="Properties\VersionInfo.cs" Overwrite="True" Lines="[assembly: System.Reflection.AssemblyVersion(&quot;$(Version)&quot;)] // Auto-generated by build process" /> </ </Target>
  7. On the product.wxs file on your WiX project, just add the following:
  8. <Product Id="12c0deff-c0de-c0de-c0de-123f422c0dea" Name="Name" Language="1033" Version ="!(bind.FileVersion.filAB3D3C60ED5901936249D5C56B6C90A6)" Manufacturer="ManyRootsofallevil" UpgradeCode="fafffaff-c0de-c0de-c0de-123f422c0dea">
    Where filAB3D3C60ED5901936249D5C56B6C90A6 is the id of your library file
  9. Finally, add the following to the wix project. Make sure this is on the initial PropertyGroup Element:
  10. <Version Condition=" '$(Version)' == ''">0.0.0.1</Version>
You can now build this using:

msbuild solution.sln /p:Version=1.3.3.7

Monday, 18 August 2014

Product Versions in MSI installers created with WIX - part 1

I must confess that in the past I used to do this manually or not at all (loud gasps) as I've never had a fully functioning CI environment but, this has changed recently so here it goes.

In essence the challenge is to change the version number of the installer every time a new build is done, so that the build number is reflected in both Windows (Control Panel -> Programs and Features ) and the file itself, e.g. installer.1.0.0.0.msi

There are two main ways of doing this, that I know of:
  • Pass the build number to the Wix Installer.
  • Get the build number from a library or executable.

In this post, I will discuss the first way, all changes unless stated are made to the wix project file (wixproj extension), so you will need to unload the project from Visual Studio or use another editor to make these changes.

We need a Property to hold the version number, which appropriately is called VersionNumber, I've made sure that this is populated with a default value, in case the build is done from Visual Studio.
<VersionNumber Condition=" '$(VersionNumber)' == '' ">0.0.0.0</VersionNumber>
I then appended the version number to the installer:
<OutputName>Installer.$(VersionNumber)</OutputName>
We then need to add a preprocessor variable to each build configuration, I've called it MSIVersion, as this is the version of the msi package:
<DefineConstants>MSIVersion=$(VersionNumber)</DefineConstants>
and finally we use this preprocessor variable in the product definition in the Product.wxs file.
<Product Id="01010101-deaf-beef-c0de-863f442f44fb" Name="MROAE" Language="1033" Version="$(var.MSIVersion)" Manufacturer="MROAE" UpgradeCode="01010101-daaa-beef-c0de-863f442f44fb">
This solution can now be build with the following command:
msbuild mysolution.sln /p:VersionNumber=1.0.0.1
A sample wixproj file can be found below with changes detailed above:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
    <PackageVersion>3.8</PackageVersion>
    <ProjectGuid>{02af16dd-0000-0000-0000-d60ba5af40cc}</ProjectGuid>
    <SchemaVersion>2.0</SchemaVersion>
    <OutputType>Package</OutputType>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
    <VersionNumber Condition=" '$(VersionNumber)' == '' ">0.0.0.0</VersionNumber>
    <Name>Installer</Name>
    <OutputName>Installer.$(VersionNumber)</OutputName>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>Debug;MSIVersion=$(VersionNumber)</DefineConstants>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
    <OutputPath>bin\$(Configuration)\</OutputPath>
    <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath>
    <DefineConstants>MSIVersion=$(VersionNumber)</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="Service.wxs" />
    <Compile Include="Product.wxs" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\Service\Service.csproj">
      <Name>Service</Name>
      <Project>{000c956c-0000-0000-0000-970884f34476}</Project>
      <Private>True</Private>
      <DoNotHarvest>True</DoNotHarvest>
      <RefProjectOutputGroups>Binaries;Content;Satellites</RefProjectOutputGroups>
      <RefTargetDir>INSTALLFOLDER</RefTargetDir>
    </ProjectReference>
  </ItemGroup>
  <ItemGroup>
    <Content Include="Icons\Product.ico" />
     </ItemGroup>
  <ItemGroup>
    <Folder Include="Icons" />
  </ItemGroup>
  <ItemGroup>
    <WixExtension Include="WixUtilExtension">
      <HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
      <Name>WixUtilExtension</Name>
    </WixExtension>
  </ItemGroup>
  <Import Project="$(WixTargetsPath)" />
  <!--
 To modify your build process, add your task inside one of the targets below and uncomment it.
 Other similar extension points exist, see Wix.targets.
 <Target Name="BeforeBuild">
 </Target>
 <Target Name="AfterBuild">
 </Target>
 -->
</Project>

And the Product File(product.wxs)

<Product Id="01010101-deaf-beef-c0de-8f3f4a2f44fb" Name="MROAE" Language="1033"
Version="$(var.MSIVersion)" Manufacturer="MROAE" 
UpgradeCode="01010101-daaa-beef-c0de-8f3f4a42f44b">

Wednesday, 26 February 2014

Issues building WiX installer, missing libraries (dlls) - Brain Dump 3

By default Visual Studio will not copy libraries that are installed in the GAC to the output folders, which means that the WiX project that looks for those libraries will fail to build as the libraries will not be there.

I'm not sure if there is a way to override this behaviour in Visual Studio (Copy Always does not seem to make a difference), so ... just remove the libraries from the GAC.

Thursday, 26 December 2013

Add/Remove Programs Product Icon with Wix

This is a very simple change that can help your application look that little bit more professional.

Just add a Add/Remove Programs Product Icon with Wix:

<Icon Id="ProductIcon" SourceFile="Icon\myicon.ico"/>    
<Property Id="ARPPRODUCTICON" Value="ProductIcon" />

See What I mean:


You need to make sure that you store myicon.ico on a directory called Icon.

Friday, 15 November 2013

Exit codes in msi installers created with Wix

There was (is?) a bug in Wix that prevented successful creation of an SSL binding in IIS 7.5, so in order to get around this issue, I wrote a custom action to do this.

A failure in this custom action will not stop the installation*, which means that the exit code will be driven by the custom action failure, which will lead to the exit code being 1603 but the product installing, since the failure is relating to setting the certificate for a webpage, this actually has no effect as the newly installed website picks up the old certificate.

The problem was in our install scripts, where we check on the exit code to ascertain whether the installation was successful, which it wasn't as the exit code was 1603 but since the app was actually there this lead to a lot of confusion and head scratching.

Thought I'd share in case somebody does something as a stupid as I did.

*I've edited the custom action code so that it does not always return success now. There was a perfectly valid reason for the code to always return a success value and I will talk about it as soon as I find it.

Selected output from the install log file:

CustomAction UpdateBinding returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
UpdateBinding. Return value 3.
INSTALL. Return value 3.

Product:  Portal -- Installation failed.
Windows Installer installed the product. Product Name: Portal. Product Version: 1.3.3.7. Product Language: 1033. Manufacturer: Yo! Ltd. Installation success or error status: 1603.

Wednesday, 10 July 2013

Run Wix installer using elevated permissions

In my last post I talked about setting a certificate binding for an IIS website from a Wix installer, which required elevated permissions in order for the operation to work.

The solution involved checking that the user was running using elevated permissions, which was simple enough but it turns out there is a far neater solution to achieve this:

 <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated" />

Sunday, 7 July 2013

Assign Certificate (Set HTTPS Binding certificate) to IIS website from Wix Installer

I'm working on this project where we have a secure website and I was tasked with creating an installer for it. After quite a few searches and not coming up with any results I went down the Custom Action route.

Not shown here is how to install the website for which we are modifying the binding.

This is very simple, it just uses IIS server manager to set the binding for the certificate, note that since this operation requires elevation of permissions, there is a check to ensure that the user is running with elevated permissions, if this is not the case then an the NotElevated custom action will be triggered, and error messaged displayed and the installation will be rolled back.

This is the Custom Action code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Deployment.WindowsInstaller;
using Microsoft.Web.Administration;
using System.Security.Cryptography.X509Certificates;
using System.Diagnostics;
using System.Security.Principal;

namespace Installer.CustomActions
{
    public class CustomActions
    {
        const string protocol = "https";
        const string bindingPattern = "*:{0}:";


        [CustomAction]
        public static ActionResult UpdateBinding(Session session)
        { 
            ActionResult result = ActionResult.Failure;
            session.Log("Start UpdateBinding.");
   if (CheckRunAsAdministrator())
   {
    bool outcome=       UpdateBinding("Portal", protocol, string.Format(bindingPattern, session["SSLPORT"]), session["CERT"], session);
     if(outcome){result = ActionResult.Success;}
                            session.Log("End UpdateBinding.");
                            return result;
   }
   else
   {
       session.Log("Not running with elevated permissions.STOP");
              session.DoAction("NotElevated");
   }
        }

        private static bool UpdateBinding(string sitename, string protocol, string port, string certSubject, Session session)
        {
            bool result=false; 
            session.Log(string.Format("Binding info (Port) {0}.", port));
            session.Log(string.Format("Certificate Subject {0}.", certSubject));

            using (ServerManager serverManager = new ServerManager())
            {
                Site site = serverManager.Sites.Where(x => x.Name == sitename).SingleOrDefault();

                X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

                store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadWrite);

                var certificate = store.Certificates.OfType<X509Certificate2>().Where(x => x.Subject == certSubject).FirstOrDefault();

                if (certificate != null)
                {
                    session.Log(string.Format("Certificate - Friendly Name: {0}. Thumbprint {1}", certificate.FriendlyName, certificate.Thumbprint));

                    site.Bindings[0].CertificateHash = certificate.GetCertHash();
                    site.Bindings[0].CertificateStoreName = store.Name;
                    site.Bindings[0].BindingInformation = port;

                    serverManager.CommitChanges();
                    result=true;
                }

                session.Log(string.Format("Could not find a certificate with Subject Name:{0}.", certSubject));

                store.Close();

            }
            return result;    
        }

        /// <summary>
        /// Check that process is being run as an administrator
        /// </summary>
        /// <returns></returns>
        private static bool CheckRunAsAdministrator()
        {
            var identity = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(identity);
            return principal.IsInRole(WindowsBuiltInRole.Administrator);
        }
    }
}
and here is the Wix markup that uses the above custom action :
<Product ....>
<!--All the rest of the stuff-->

    <Binary Id="CA" SourceFile="$(var.Installer.CustomActions.TargetDir)Installer.CustomActions.CA.dll"/>

    <CustomAction Id="UpdateBinding" BinaryKey="CA" DllEntry="UpdateBinding" Execute="immediate" Return="check" />

    <CustomAction Id="NotElevated" Error="Ensure that the Installer is Run with elevated permissions (i.e. Run as Administrator)" />

    <InstallExecuteSequence>
      <Custom Action="UpdateBinding" After="InstallFinalize">NOT Installed</Custom>
    </InstallExecuteSequence>
</Product>

Saturday, 10 November 2012

Trace logging with the Enterprise Library for MS Dynamics CRM 2011 plug-ins - part 2

In part one of this series I described the changes needed to use the trace logging capabilities of the enterprise library, in this post I shall describe how to add these changes using Wix.

The more eagled eyed readers, will notice that the listeners are different from the last time, this is because we are actually using a private queue on the database server to log the Trace messages to. These are then processed by the Enterprise Library MSMQ Distributor service, I shall discuss this in detail in an upcoming post.

I've not managed to insert the configSections element at the beginning of CrmAsyncService.exe.config file, which is where it needs to be, so I just deleted what it was there, added the configSections element and re-added what was originally there. It feels too much like a hack but ...

 Wix Sample
 <?xml version="1.0" encoding="UTF-8"?>
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
   <Fragment >
 
     <Component Id="pluginlogging" Guid="BA77335E-ADF1-4037-9881-68E116BA543D" Directory="dirB50C76F5A59FB10334E162992F65AAAA" KeyPath="yes">
       <Condition>DYNAMICS</Condition>
       <util:XmlConfig Id="web.logging"  File="[DYNAMICSCRMWEB]\web.config" Action="create"
               ElementPath="/configuration/configSections" On="install"  Node="document" Sequence="1" VerifyPath="/configuration/configSections/section[\[]@name='loggingConfiguration'[\]]" >
         <![CDATA[<section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" /> ]]>
       </util:XmlConfig>
 
       <util:XmlConfig Id="webloggingConfiguration" Action="create" ElementPath="/configuration"   File="[DYNAMICSCRMWEB]\web.config" Node="document" On="install" Sequence="2" VerifyPath="/configuration/loggingConfiguration/listeners">
         <![CDATA[<loggingConfiguration name="" tracingEnabled="true" defaultCategory="Trace">
     <listeners>
       <add name="Message Queuing Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.MsmqTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.MsmqTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         queuePath="FormatName:Direct=OS:[SQLHOSTNAME]\private$\logging" formatter="Binary Log Message Formatter"
         timeToReachQueue="10.00:00:00" timeToBeReceived="10.00:00:00"
         recoverable="true" useDeadLetterQueue="true" traceOutputOptions="None" />
        <add name="Event Log Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         source="Enterprise Library Logging" formatter="Text Formatter" />
     </listeners>
     <formatters>
       <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
         name="Text Formatter" />
       <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         name="Binary Log Message Formatter" />
     </formatters>
     <categorySources>
       <add switchValue="All" name="Trace">
         <listeners>
           <add name="Message Queuing Trace Listener" />
         </listeners>
       </add>
       <add switchValue="All" name="Error">
         <listeners>
           <add name="Message Queuing Trace Listener" />
         </listeners>
       </add>
     </categorySources>
     <specialSources>
       <allEvents switchValue="All" name="All Events" />
       <notProcessed switchValue="All" name="Unprocessed Category" />
       <errors switchValue="All" name="Logging Errors &amp; Warnings">
         <listeners>
           <add name="Event Log Trace Listener" />
         </listeners>
       </errors>
     </specialSources>
   </loggingConfiguration>]]>
       </util:XmlConfig>
 
 
       <util:XmlConfig Id="asyncloggingConfiguratiodn" Action="delete" ElementPath="/configuration"   File="[DYNAMICSCRM]\Server\bin\CrmAsyncService.exe.config" Node="element"
                  On="install" Sequence="3" VerifyPath="runtime" />
 
       <util:XmlConfig Id="asynclogging" Action="create" ElementPath="/configuration"
                       File="[DYNAMICSCRM]\Server\bin\CrmAsyncService.exe.config" Node="document" On="install" Sequence="4" VerifyPath="/configuration/configSections/section[\[]@name='loggingConfiguration'[\]]" >
         <![CDATA[<configSections><section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" /></configSections>]]>
       </util:XmlConfig>
 
       <util:XmlConfig Id="asyncloggingmlarky" Action="create" ElementPath="/configuration"
                       File="[DYNAMICSCRM]\Server\bin\CrmAsyncService.exe.config" Node="document" On="install" Sequence="5" VerifyPath="/configuration/runtime" >
         <![CDATA[<runtime><gcServer enabled="true"/>
         <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
           <dependentAssembly>
             <assemblyIdentity name="Microsoft.Crm.Sdk" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
             <bindingRedirect oldVersion="4.0.0.0-5.0.0.0" newVersion="5.0.0.0"/>
           </dependentAssembly>
         </assemblyBinding>
       </runtime>]]>
       </util:XmlConfig>
 
       <util:XmlConfig Id="asyncloggingConfiguration" Action="create" ElementPath="/configuration"
                       File="[DYNAMICSCRM]\Server\bin\CrmAsyncService.exe.config" Node="document" On="install" Sequence="6" VerifyPath="/configuration/loggingConfiguration/listeners" >
         <![CDATA[<loggingConfiguration name="" tracingEnabled="true" defaultCategory="Trace">
     <listeners>
       <add name="Message Queuing Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.MsmqTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.MsmqTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         queuePath="FormatName:Direct=OS:[SQLHOSTNAME]\private$\logging" formatter="Binary Log Message Formatter"
         timeToReachQueue="10.00:00:00" timeToBeReceived="10.00:00:00"
         recoverable="true" useDeadLetterQueue="true" traceOutputOptions="None" />
        <add name="Event Log Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         source="Enterprise Library Logging" formatter="Text Formatter" />
     </listeners>
     <formatters>
       <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"
         name="Text Formatter" />
       <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.BinaryLogFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         name="Binary Log Message Formatter" />
     </formatters>
     <categorySources>
       <add switchValue="All" name="Trace">
         <listeners>
           <add name="Message Queuing Trace Listener" />
         </listeners>
       </add>
       <add switchValue="All" name="Error">
         <listeners>
           <add name="Message Queuing Trace Listener" />
         </listeners>
       </add>
     </categorySources>
     <specialSources>
       <allEvents switchValue="All" name="All Events" />
       <notProcessed switchValue="All" name="Unprocessed Category" />
       <errors switchValue="All" name="Logging Errors &amp; Warnings">
         <listeners>
           <add name="Event Log Trace Listener" />
         </listeners>
       </errors>
     </specialSources>
   </loggingConfiguration>]]>
       </util:XmlConfig>
       <File Id="fileA8FAD71029831AC3655E19B9142ABCD"  Source="..\..\bin\Microsoft.Practices.EnterpriseLibrary.Common.dll" >
         <CopyFile Id="cfile1" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfilea" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
       <File Id="fileA6A5ADE82FC3926C6591208B146ABCD"  Source="..\..\bin\Microsoft.Practices.EnterpriseLibrary.Data.dll" >
         <CopyFile Id="cfile2" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfileb" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
       <File Id="fileA87A152C5D90176A5F35A9ED31AABCD"  Source="..\..\bin\Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll" >
         <CopyFile Id="cfile3" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfilec" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
       <File Id="fileA83ADD8942E77F370200E658EAEABCD"  Source="..\..\bin\Microsoft.Practices.EnterpriseLibrary.Logging.dll" >
         <CopyFile Id="cfile4" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfiled" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
       <File Id="fileAE5A8C078462AB1F516A8987676ABCD"  Source="..\..\bin\Microsoft.Practices.ServiceLocation.dll" >
         <CopyFile Id="cfile5" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfilee" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
       <File Id="fileA5CDA0533279F89ACC36D7BDCD6ABCD"  Source="..\..\bin\Microsoft.Practices.Unity.dll" >
         <CopyFile Id="cfile6" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfilef" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
       <File Id="fileAC309FAF27707DCE67A3664FA1FABCD"  Source="..\..\bin\Microsoft.Practices.Unity.Interception.dll" >
         <CopyFile Id="cfile7" DestinationProperty="DYNAMICSBIN"/>
         <CopyFile Id="cfileg" DestinationProperty="DYNAMICSWEBBIN"/>
       </File>
     </Component>
   </Fragment>
   <Fragment>
     <DirectoryRef  Id="INSTALLLOCATION">
       <Directory Id="dirB50C76F5A59FB10334E162992F65AAAA" />
     </DirectoryRef>
   </Fragment>
 </Wix>
Property Definition Sample
 <Property Id="DYNAMICSCRMWEB" Value="C:\Program Files\Microsoft Dynamics CRM\CRMWeb">
   <RegistrySearch Id="Dynamicscrmweb_RegKey" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\MSCRM" Name="WebSitePath" Win64="yes"/>
 </Property>
 
 <Property Id="DYNAMICSCRM" >
   <RegistrySearch Id="Dynamics_RegKey" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\MSCRM" Name="CRM_Server_InstallDir" Win64="yes"/>
 </Property>
 
 <Property Id="DYNAMICS" >
   <RegistrySearch Id="DynamicsgKey" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\MSCRM" Name="roles" Win64="yes"/>
 </Property>
 
 <Property Id="DYNAMICSWEBBIN"/>
 
 <SetProperty Id="DYNAMICSWEBBIN" Value="[DYNAMICSCRMWEB]\bin" After="CostFinalize"/>
 
 <Property Id="DYNAMICSBIN"/>
 
 <SetProperty Id="DYNAMICSBIN" Value="[DYNAMICSCRM]\Server\bin" After="CostFinalize"/>
The next post of the series can be found here