Installing a User Account Service Unattended (Part 2)

December 31, 2011

one comment


The previous post discussed about setting up the unattended service. Now that our shiny new service is ready for delivery, we need to package it inside a Windows Installer MSI.


There are two major alternatives to install a .NET service. The classic one being fully controlled by MSI in Win32 level; the other is overriding methods of System.Configuration.Install leaving it to the CLR via InstallUtil. Or you can combine both methods.


This post is about how to install a .NET service using WiX.


Packaging the service in WiX


Prerequisites: Visual Studio (2005/2008/2010 or higher), WiX toolset




  1. In Visual Studio, create a new Windows Installer XML setup project.


  2. We will need some UI to allow the user to enter the service account credentials. Add reference to WixUIExtension.dll

     



  3. Add the service component:
  4.     <ComponentGroup Id=”ProductComponents” Directory=”INSTALLFOLDER”>
    <Component Id=”SampleService” Guid=”D2C707DF-E365-4318-A466-863A7F4A4A74″ SharedDllRefCount=”yes”>
    <File Id=”SampleService.exe” Name=”SampleService.exe” Source=”$(var.BinFolder)\SampleService.exe” Vital=”yes” />
    <File Id=”SampleService.exe.config” Name=”SampleService.exe.config” Source=”$(var.BinFolder)\SampleService.exe.config” Vital=”yes” />
    </Component>
    </ComponentGroup>


  5. Now we need to add properties to hold the username and password of the service account. Given the sensitivity of these properties, we’ll mark them as secure and hidden:
  6.         <Property Id=”SVCUSERNAME” Secure=”yes” Hidden=”yes” />
    <Property Id=”SVCPASSWORD” Secure=”yes” Hidden=”yes” />


  7. Optionally we can add a default value for the username via custom action:
  8.     <CustomAction Id=”CA_Set_SVCUSERNAME” Property=”SVCUSERNAME” Value=”[ComputerName]\[USERNAME]“ Execute=”firstSequence” />
    This immediate custom action scheduled to run in the UI sequence:
        <InstallUISequence>
    <Custom Action=”CA_Set_SVCUSERNAME” After=”AppSearch”>NOT Installed</Custom>
    </InstallUISequence>


  9. Include InstallUtilLib.dll in the binary table. While we could call InstallUtil.exe as well, this option guarantees silent execution.
  10.     <Binary Id=”InstallUtil” SourceFile=’$(env.windir)\Microsoft.NET\Framework\v4.0.30319\InstallUtilLib.dll’ />

  11. The service is installed during the Execute phase so it’s time add the custom actions that will run InstallUtil. Each action requires a type 51 set-a-property action counterpart to pass the CustomActionData to deferred execution.
  12.     <CustomAction Id=’SampleService.Install.SetProperty’ Property=’SampleService.Install’ Value=’/installtype=notransaction /action=install /LogFile= /username=[SVCUSERNAME] /password=[SVCPASSWORD] /unattended “[#SampleService.exe]” “[#SampleService.exe.config]“‘ />
    <CustomAction Id=’SampleService.Install’ BinaryKey=’InstallUtil’ DllEntry=’ManagedInstall’ Execute=’deferred’/>
    <CustomAction Id=’SampleService.Commit.SetProperty’ Property=’SampleService.Commit’ Value=’/installtype=notransaction /action=commit /LogFile= /username=[SVCUSERNAME] /password=[SVCPASSWORD] /unattended “[#SampleService.exe]” “[#SampleService.exe.config]“‘ />
    <CustomAction Id=’SampleService.Commit’ BinaryKey=’InstallUtil’ DllEntry=’ManagedInstall’ Execute=’commit’ />
    <CustomAction Id=’SampleService.Rollback.SetProperty’ Property=’SampleService.Rollback’ Value=’/installtype=notransaction /action=rollback /LogFile= “[#SampleService.exe]“‘ />
    <CustomAction Id=’SampleService.Rollback’ BinaryKey=’InstallUtil’ DllEntry=’ManagedInstall’ Execute=’rollback’ />
    <CustomAction Id=’SampleService.Uninstall.SetProperty’ Property=’SampleService.Uninstall’ Value=’/installtype=notransaction /action=uninstall /LogFile= “[#SampleService.exe]“‘ />
    <CustomAction Id=’SampleService.Uninstall’ BinaryKey=’InstallUtil’ DllEntry=’ManagedInstall’ Execute=’deferred’ Return=’ignore’ />






    Note: the service must have an app.config denoting its supported framework runtime version. Without it, the notorious error 1001 will follow once the service gets installed, failing the entire installation. The app.config defined as follows:

    <configuration>
    <startup>
    <supportedRuntime version=”v4.0.30319″/>
    </startup>
    </configuration>

    See in the above example how the config path being passed as an argument ([#SampleService.exe.config]) after the service path.


  13. Now it’s time to allow users to set the service account credentials through a form dialog.

  14. 8.1 The following is a simple implementation loosely based on the WixUI_InstallDir.

        <UI Id=”WixUI_ServiceInstall”>
    <TextStyle Id=”WixUI_Font_Normal” FaceName=”Tahoma” Size=”8″ />
    <TextStyle Id=”WixUI_Font_Bigger” FaceName=”Tahoma” Size=”12″ />
    <TextStyle Id=”WixUI_Font_Title” FaceName=”Tahoma” Size=”9″ Bold=”yes” />

    <Property Id=”DefaultUIFont” Value=”WixUI_Font_Normal” />
    <Property Id=”WixUI_Mode” Value=”InstallDir” />
    <Property Id=”WIXUI_INSTALLDIR” Value=”INSTALLFOLDER” />

    <DialogRef Id=”BrowseDlg” />
    <DialogRef Id=”DiskCostDlg” />
    <DialogRef Id=”ErrorDlg” />
    <DialogRef Id=”FatalError” />
    <DialogRef Id=”FilesInUse” />
    <DialogRef Id=”MsiRMFilesInUse” />
    <DialogRef Id=”PrepareDlg” />
    <DialogRef Id=”ProgressDlg” />
    <DialogRef Id=”ResumeDlg” />
    <DialogRef Id=”UserExit” />

    <Publish Dialog=”BrowseDlg” Control=”OK” Event=”DoAction” Value=”WixUIValidatePath” Order=”3″>1</Publish>
    <Publish Dialog=”BrowseDlg” Control=”OK” Event=”SpawnDialog” Value=”InvalidDirDlg” Order=”4″><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>

    <Publish Dialog=”ExitDialog” Control=”Finish” Event=”EndDialog” Value=”Return” Order=”999″>1</Publish>

    <Publish Dialog=”WelcomeDlg” Control=”Next” Event=”NewDialog” Value=”InstallDirDlg”>NOT Installed</Publish>
    <Publish Dialog=”WelcomeDlg” Control=”Next” Event=”NewDialog” Value=”VerifyReadyDlg”>Installed AND PATCH</Publish>

    <Publish Dialog=”InstallDirDlg” Control=”Back” Event=”NewDialog” Value=”WelcomeDlg”>1</Publish>
    <Publish Dialog=”InstallDirDlg” Control=”Next” Event=”SetTargetPath” Value=”[WIXUI_INSTALLDIR]“ Order=”1″>1</Publish>
    <Publish Dialog=”InstallDirDlg” Control=”Next” Event=”DoAction” Value=”WixUIValidatePath” Order=”2″>NOT WIXUI_DONTVALIDATEPATH</Publish>
    <Publish Dialog=”InstallDirDlg” Control=”Next” Event=”SpawnDialog” Value=”InvalidDirDlg” Order=”3″><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
    <Publish Dialog=”InstallDirDlg” Control=”Next” Event=”NewDialog” Value=”AccountInformationDlg” Order=”4″>WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID=”1″</Publish>
    <Publish Dialog=”InstallDirDlg” Control=”ChangeFolder” Property=”_BrowseProperty” Value=”[WIXUI_INSTALLDIR]“ Order=”1″>1</Publish>
    <Publish Dialog=”InstallDirDlg” Control=”ChangeFolder” Event=”SpawnDialog” Value=”BrowseDlg” Order=”2″>1</Publish>

    <Publish Dialog=”AccountInformationDlg” Control=”Back” Event=”NewDialog” Value=”InstallDirDlg”>1</Publish>
    <Publish Dialog=”AccountInformationDlg” Control=”Next” Event=”NewDialog” Value=”VerifyReadyDlg”>1</Publish>

    <Publish Dialog=”VerifyReadyDlg” Control=”Back” Event=”NewDialog” Value=”InstallDirDlg” Order=”1″>NOT Installed</Publish>
    <Publish Dialog=”VerifyReadyDlg” Control=”Back” Event=”NewDialog” Value=”MaintenanceTypeDlg” Order=”2″>Installed AND NOT PATCH</Publish>
    <Publish Dialog=”VerifyReadyDlg” Control=”Back” Event=”NewDialog” Value=”WelcomeDlg” Order=”2″>Installed AND PATCH</Publish>

    <Publish Dialog=”MaintenanceWelcomeDlg” Control=”Next” Event=”NewDialog” Value=”MaintenanceTypeDlg”>1</Publish>

    <Publish Dialog=”MaintenanceTypeDlg” Control=”RepairButton” Event=”NewDialog” Value=”VerifyReadyDlg”>1</Publish>
    <Publish Dialog=”MaintenanceTypeDlg” Control=”RemoveButton” Event=”NewDialog” Value=”VerifyReadyDlg”>1</Publish>
    <Publish Dialog=”MaintenanceTypeDlg” Control=”Back” Event=”NewDialog” Value=”MaintenanceWelcomeDlg”>1</Publish>

    <Property Id=”USERVALIDATED” Value=”0″ />
    <Property Id=”ARPNOMODIFY” Value=”1″ />
    </UI>


    8.2 The AccountInformationDlg dialog contains the SVCUSERNAME and SVCUSERNAME fields for the user to fill in:

        <UI>
    <Dialog Id=”AccountInformationDlg” Width=”370″ Height=”270″ Title=”!(loc.InstallDirDlg_Title)”>
    <Control Id=”Next” Type=”PushButton” X=”236″ Y=”243″ Width=”56″ Height=”17″ Default=”yes” Text=”!(loc.WixUINext)” />
    <Control Id=”Back” Type=”PushButton” X=”180″ Y=”243″ Width=”56″ Height=”17″ Text=”!(loc.WixUIBack)” />
    <Control Id=”Cancel” Type=”PushButton” X=”304″ Y=”243″ Width=”56″ Height=”17″ Cancel=”yes” Text=”!(loc.WixUICancel)”>
    <Publish Event=”SpawnDialog” Value=”CancelDlg”>1</Publish>
    </Control>
    <Control Id=”Description” Type=”Text” X=”25″ Y=”23″ Width=”280″ Height=”15″ Transparent=”yes” NoPrefix=”yes” Text=”Set user account information and click Next to continue” />
    <Control Id=”Title” Type=”Text” X=”15″ Y=”6″ Width=”200″ Height=”15″ Transparent=”yes” NoPrefix=”yes” Text=”{\WixUI_Font_Title}User Account Information” />
    <Control Id=”BannerBitmap” Type=”Bitmap” X=”0″ Y=”0″ Width=”370″ Height=”44″ TabSkip=”no” Text=”!(loc.InstallDirDlgBannerBitmap)” />
    <Control Id=”BannerLine” Type=”Line” X=”0″ Y=”44″ Width=”370″ Height=”0″ />
    <Control Id=”BottomLine” Type=”Line” X=”0″ Y=”234″ Width=”370″ Height=”0″ />
    <Control Id=”UserLabel” Type=”Text” X=”20″ Y=”60″ Width=”290″ Height=”13″ Text=”User Account (domain\user):” />
    <Control Id=”UserEdit” Type=”Edit” X=”20″ Y=”74″ Width=”320″ Height=”18″ Property=”SVCUSERNAME” />
    <Control Id=”PasswordLabel” Type=”Text” X=”20″ Y=”100″ Width=”290″ Height=”13″ Text=”Password:” />
    <Control Id=”PasswordEdit” Type=”Edit” Password=”yes” X=”20″ Y=”114″ Width=”320″ Height=”18″ Property=”SVCPASSWORD”/>
    </Dialog>
    </UI>

    8.3 Finally add the UI references in the <Product> element:

        <UIRef Id=”WixUI_Common” />
    <UIRef Id=”WixUI_ServiceInstall” />

    9. The project is ready for build. Update product properties and files and that’s it.


     

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

one comment

  1. north face jackets for menNovember 5, 2012 ב 15:00

    Hmm is anyone else experiencing problems with the pictures on this blog loading? I’m trying to determine if its a problem on my end or if it’s the blog. Any feed-back would be greatly appreciated.

    Reply