【问题标题】:Web application install with initial IIS settings; using WiX, need upgrade files, NOT changing IIS settings使用初始 IIS 设置安装 Web 应用程序;使用 WiX,需要升级文件,不更改 IIS 设置
【发布时间】:2012-02-24 12:10:44
【问题描述】:

我有一个 WiX 安装项目,其中包括虚拟目录的 IIS 设置和应用程序池的应用程序设置。初始安装后,客户将从 wxs 中设置的默认网络服务更改应用程序池标识。

如何构建一个可以更新 Web 文件但不将 IIS 设置、应用程序池标识更改回网络服务的更新安装程序?

ComponentGroupRef Id="WebPublishCmp" 是要发布的 Web 文件的初始热输出。

我已尝试使用 TorchPyro 构建小升级,但我遇到了 Torch diff 未检测到更改的问题(这是另一个 Stack 溢出问题的另一个问题)。

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension">

  <?include Config.wxi ?>

  <Product
    Id="E3105F82-0460-4C3C-8F6C-778405E81F61"
    Name="Website"
    Language="1033"
    Version="1.0.0.1"
    Manufacturer="Website"
    UpgradeCode="E3105F82-0460-4C3C-8F6C-778405E81F61">

    <Package
      InstallerVersion="200" Compressed="yes" />

    <Media
      Id="1"
      Cabinet="media1.cab"
      EmbedCab="yes" />

    <Property Id="WIXUI_INSTALLDIR" Value="INSTALLLOCATION" />
    <UIRef Id="CustomWixUI_InstallDir"/>

    <FeatureRef Id="InitialFeature"/>

  </Product>

  <Fragment>
    <Feature Id="InitialFeature" Title="Initial (Full)" Level="1">
      <ComponentGroupRef Id="WebPublishCmp"/>
      <ComponentRef Id="IIS.Component"/>
    </Feature>

    <Feature Id="WebFilesFeature" Title="Website (Files)" Level="1">
      <ComponentGroupRef Id="WebPublishCmp"/>
    </Feature>


  </Fragment>

  <Fragment>
    <Component Id="IIS.Component" Guid="6FAD9EC7-D2B0-4471-A657-C8AF5F6F707F" KeyPath="yes" Directory="INSTALLLOCATION">
      <iis:WebSite Id="DefaultWebSite" Description="$(var.WebSiteName)" Directory="INSTALLLOCATION" >
        <iis:WebAddress Id="AllUnassigned" Port="80"/>
      </iis:WebSite>
      <iis:WebAppPool Id="WebsiteAppPool" Name="App" Identity="networkService" />
      <iis:WebVirtualDir Id="My.VirtualDir" Alias="App" Directory="INSTALLLOCATION" WebSite="DefaultWebSite">
        <iis:WebApplication Id="Application" Name="App" WebAppPool="WebsiteAppPool"/>
      </iis:WebVirtualDir>
    </Component>
  </Fragment>

  <Fragment>
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLLOCATION" Name="Website">
        </Directory>
      </Directory>
    </Directory>
  </Fragment>
</Wix>

我正在使用:

  • WiX 3.5、3.6
  • Visual Studio 2010

【问题讨论】:

    标签: wix windows-installer installation wix3.5


    【解决方案1】:

    我提前为冗长的回答道歉:

    我建议将您的网站和内容保留在两个单独的功能中,然后让它们选择通过 UI 或命令行参数提供安装所需的任何变量。如果您使用"Remember Property" pattern,那么您可以回忆在更改或升级安装时使用的变量(通读最后的 cmets,有一种稍微简单的方法)。

    这允许安装产品的人使用给定变量设置所有内容,或自行设置 IIS 网站并仅安装网站内容。

    这也与 MajorUpgrades 配合得很好。我目前在您提供的代码中没有看到升级信息,因此您应该查看MajorUpgrades vs patches(主要升级更容易)

    <MajorUpgrade AllowDowngrades="no" AllowSameVersionUpgrades="yes" Schedule="afterInstallInitialize" DowngradeErrorMessage="A later version of of this product is already installed. Setup will now exit."/>
    

    请记住,通过 $(var.name) 访问的变量在 MSI 编译时使用,而通过括号 [MY_VARIABLE] 访问的公共变量在安装时使用。公共变量可以通过 MSI UI 公开,或通过命令行提供给 msiexec(我将其用于静默安装和/或指定日志文件)

    以下是以下示例的摘要:

    • Configuration.wxi - 该文件实现了“记住”的属性
    • Product.wxs - 与您的大部分相似,但也包括 MajorUpgrades、网站和内容的单独功能以及包含 UiFlow
    • IISConfiguration.wxs - 包含 IIS 网站、AppPool 和 AppPool 用户的片段,使用安装时提供的变量
    • UIFlow.wxs - 定义要使用的 UI 流程,它使用 WixUI FeatureTree 插件,您的 UI 可能需要其他东西
    • UIDialogs.wxs - 这是安装中使用的变量暴露给 UI 的地方

    Configuration.wxi:

    <?xml version="1.0" encoding="utf-8" ?>
    <Include xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension"
         xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
        
        <!-- The RegistrySearch elements will populate these properties with values from the registry IF they exist there, otherwise the default values will be used -->
        <Property Id="REG_WEBSITE_NAME" Value="WebsiteName" >
            <RegistrySearch Id="WEB_WEBSITE_NAME_Remembered" Root="HKLM" Key="SOFTWARE\PRODUCT_NAME" Name="Website_Name" Type="raw" />
        </Property>
        <Property Id="REG_WEB_APP_POOL_NAME" Value="PoolName" >
            <RegistrySearch Id="WEB_APP_POOL_NAME_Remembered" Root="HKLM" Key="SOFTWARE\PRODUCT_NAME" Name="WebApp_PoolName" Type="raw" />
        </Property>
        <Property Id="REG_WEB_APP_POOL_IDENTITY_DOMAIN">
            <RegistrySearch Id="WEB_APP_POOL_IDENTITY_DOMAIN_Remembered" Root="HKLM" Key="SOFTWARE\PRODUCT_NAME" Name="WebApp_PoolIdentityDomain" Type="raw" />
        </Property>
        <Property Id="REG_WEB_APP_POOL_IDENTITY_USERNAME" Value="NetworkService" >
            <RegistrySearch Id="WEB_APP_POOL_IDENTITY_USERNAME_Remembered" Root="HKLM" Key="SOFTWARE\PRODUCT_NAME" Name="WebApp_PoolIdentityUsername" Type="raw" />
        </Property>
        <!-- Notice that the password is NOT stored in the registry and is hidden so it's not shown in logs -->
        <Property Id="WEB_APP_POOL_IDENTITY_PWD" Hidden="yes" />
    
        <!-- This is the compnent that actually writes the values to the registry on install -->
        <Component Id="C_RegistryEntries" Directory="INSTALLLOCATION">
            <RegistryValue Root="HKLM" Key="SOFTWARE\ProviderWebsites" Name="Website_Name"                  Type="string" Value="[WEBSITE_NAME]"/>
            <RegistryValue Root="HKLM" Key="SOFTWARE\ProviderWebsites" Name="WebApp_PoolName"               Type="string" Value="[WEB_APP_POOL_NAME]"/>
            <RegistryValue Root="HKLM" Key="SOFTWARE\ProviderWebsites" Name="WebApp_PoolIdentityDomain"     Type="string" Value="[WEB_APP_POOL_IDENTITY_DOMAIN]"/>
            <RegistryValue Root="HKLM" Key="SOFTWARE\ProviderWebsites" Name="WebApp_PoolIdentityUsername"   Type="string" Value="[WEB_APP_POOL_IDENTITY_USERNAME]"/>
        </Component>
    
        <!-- These CustomActions set the property that are used for the install from the registry values (These actions are only run under the conditions in the sequences below) -->
        <CustomAction Id='SetWebAppName'                    Property='WEBSITE_NAME'                     Value='[REG_WEBSITE_NAME]'/>
        <CustomAction Id='SetWebAppPoolName'                Property='WEB_APP_POOL_NAME'                Value='[REG_WEB_APP_POOL_NAME]'/>
        <CustomAction Id='SetWebAppPoolIdentityDomain'      Property='WEB_APP_POOL_IDENTITY_DOMAIN'     Value='[REG_WEB_APP_POOL_IDENTITY_DOMAIN]'/>
        <CustomAction Id='SetWebAppPoolIdentityUsername'    Property='WEB_APP_POOL_IDENTITY_USERNAME'   Value='[REG_WEB_APP_POOL_IDENTITY_USERNAME]'/>
        
        <!-- The CustomActions above that set the variables used in the installation are only run if they were not supplied by the command line -->
        <InstallUISequence>
            <Custom Action='SetWebAppName'                  After='AppSearch'>REG_WEBSITE_NAME                      AND (NOT WEBSITE_NAME)</Custom>
            <Custom Action='SetWebAppPoolName'              After='AppSearch'>REG_WEB_APP_POOL_NAME                 AND (NOT WEB_APP_POOL_NAME)</Custom>
            <Custom Action='SetWebAppPoolIdentityDomain'    After='AppSearch'>REG_WEB_APP_POOL_IDENTITY_DOMAIN      AND (NOT WEB_APP_POOL_IDENTITY_DOMAIN)</Custom>
            <Custom Action='SetWebAppPoolIdentityUsername'  After='AppSearch'>REG_WEB_APP_POOL_IDENTITY_USERNAME    AND (NOT WEB_APP_POOL_IDENTITY_USERNAME)</Custom>
        </InstallUISequence>
        <InstallExecuteSequence>
            <!-- After='RemoveExistingProducts' is used under this sequence because of the use of MajorUpgrades -->
            <Custom Action='SetWebAppName'                  After='RemoveExistingProducts'>REG_WEBSITE_NAME                     AND (NOT WEBSITE_NAME)</Custom>
            <Custom Action='SetWebAppPoolName'              After='RemoveExistingProducts'>REG_WEB_APP_POOL_NAME                    AND (NOT WEB_APP_POOL_NAME)</Custom>
            <Custom Action='SetWebAppPoolIdentityDomain'    After='RemoveExistingProducts'>REG_WEB_APP_POOL_IDENTITY_DOMAIN     AND (NOT WEB_APP_POOL_IDENTITY_DOMAIN)</Custom>
            <Custom Action='SetWebAppPoolIdentityUsername'  After='RemoveExistingProducts'>REG_WEB_APP_POOL_IDENTITY_USERNAME   AND (NOT WEB_APP_POOL_IDENTITY_USERNAME)</Custom>
        </InstallExecuteSequence>
    
    </Include>
    

    产品.wxs:

    <?xml version="1.0" encoding="UTF-8"?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension"
         xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns:netfx="http://schemas.microsoft.com/wix/NetFxExtension">
    
        <!--NEVER EVER EVER EVER CHANGE THE UPGRADE CODE!!!!!!!!!!!!!!! -->
        <?define UpgradeCode="PUT-GUID-HERE" ?>
    
        <Product Id="*" Name="ProductName" Language="1033" Version="X.X.X.X" Manufacturer="XYZ" UpgradeCode="$(var.UpgradeCode)">
            <Package InstallerVersion="200" Compressed="yes" />
    
            <!-- This includes our properties that implement the "Remember Property" pattern -->
            <?include Configuration.wxi ?>
    
            <Media Id="1" Cabinet="media.cab" EmbedCab="yes" />
    
            <MajorUpgrade AllowDowngrades="no" AllowSameVersionUpgrades="yes" Schedule="afterInstallInitialize"
                          DowngradeErrorMessage="A later version of this product is already installed. Setup will now exit."/>
    
            <!-- Creating default directory structure (INSTALLLOCATION be override by user, but it starts in Program Files) -->
            <Directory Id="TARGETDIR" Name="SourceDir">
                <Directory Id='ProgramFilesFolder' Name='PFiles'>
                    <Directory Id="INSTALLLOCATION" Name="TheDefaultInstallFolderName">
    
                    </Directory>
                </Directory>
            </Directory>
    
            <Feature Id="F_Content" Title="Content" Level="1" Description="The website content" ConfigurableDirectory="INSTALLLOCATION">
                <ComponentRef Id="C_RegistryEntries"/>
                <!-- The C_WebAppContent can either be generated by the WiX tool "heat", or a hand-crafted set of content, this component is not included in this example -->
                <ComponentGroupRef Id="C_WebAppContent" />
            </Feature>
    
            <Feature Id="F_IISWebsite" Title="IIS Website" Description="The IIS website and application pool" Level="1">
                <ComponentRef Id="C_IISWebsite" />
            </Feature>
    
            <InstallExecuteSequence>
            </InstallExecuteSequence>
    
            <!-- Specify UI -->
            <UIRef Id="UIFlow" />
        </Product>
    </Wix>
    

    IISConfiguration.wxs:

    <?xml version="1.0" encoding="utf-8" ?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension"
         xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    
        <Fragment>      
            <DirectoryRef Id="INSTALLLOCATION">
                <Component Id="C_IISWebsite" Guid="{PUT-GUID-HERE}" KeyPath="yes">
                    <!-- This does not create a user, it's just an object that's referenced by the WebAppPool component -->
                    <util:User Id="WebAppPoolUser" CreateUser="no" Name="[WEB_APP_POOL_IDENTITY_USERNAME]" 
                               Password="[WEB_APP_POOL_IDENTITY_PWD]" Domain="[WEB_APP_POOL_IDENTITY_DOMAIN]"/>
    
                    <!-- The "Identity" attritbute below needs to be set to "other" to use the util:User defined above -->
                    <iis:WebAppPool Id="WebAppPool" Name="[WEB_APP_POOL_NAME]" Identity="other" User="WebAppPoolUser"/>
                    
                    <iis:WebSite Id="DefaultWebSite" Description="[WEBSITE_NAME]" Directory="INSTALLLOCATION" >
                        <iis:WebAddress Id="AllUnassigned" Port="80"/>
                    </iis:WebSite>
                    
                    <iis:WebVirtualDir Id="My.VirtualDir" Alias="App" Directory="INSTALLLOCATION" WebSite="DefaultWebSite">
                        <iis:WebApplication Id="Application" Name="App" WebAppPool="WebAppPool"/>
                    </iis:WebVirtualDir>
                </Component>
            </DirectoryRef>
        </Fragment>
    </Wix>
    

    UIFlow.wxs:

    <?xml version="1.0" encoding="utf-8" ?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
        <Fragment>
            <UI Id="UIFlow">
                <!-- This uses the WixUI plugin -->
                <UIRef Id="WixUI_FeatureTree" />
                <UIRef Id="WixUI_ErrorProgressText" />
    
                <!-- Injection of custom UI. -->
                <DialogRef Id="IisSetupDlg" />
                
                <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="IisSetupDlg" Order="3">LicenseAccepted = "1"</Publish>
                <Publish Dialog="CustomizeDlg" Control="Back" Event="NewDialog" Value="PoolSettingsDlg">1</Publish>
            </UI>
        </Fragment>
    </Wix>
    

    UIDialogs.wxs:

    <?xml version="1.0" encoding="utf-8" ?>
    <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
        <Fragment>
            <UI>
                <Dialog Id="IisSetupDlg" Width="370" Height="270" Title="IIS Settings - [ProductName]" NoMinimize="yes">                
                    <!-- Web App details prompt -->
                    <Control Id="WebsiteNameLabel" Type="Text" X="45" Y="53" Width="100" Height="15" TabSkip="no" Text="&amp;Website Name:" />
                    <Control Id="WebsiteNameEdit" Type="Edit" X="45" Y="65" Width="220" Height="18" Property="WEBSITE_NAME" Text="{80}" />
                    
                    <!-- Back button -->
                    <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="&amp;Back">
                        <Publish Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
                    </Control>
                    
                    <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="&amp;Next">
                        <Publish Event="NewDialog" Value="PoolSettingsDlg">
                            <!--if settings are correct, allow next dialog-->
                            <![CDATA[WEBSITE_NAME <> ""]]>
                        </Publish>
                    </Control>
                    
                    <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="Cancel">
                        <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
                    </Control>
                    
                    <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="WixUI_Bmp_Banner" />
                    <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes">
                        <Text>Please enter IIS Configuration</Text>
                    </Control>
                    
                    <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0" />
                    <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes">
                        <Text>{\WixUI_Font_Title}IIS Settings</Text>
                    </Control>
                    
                    <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
                </Dialog>
    
                <Dialog Id="PoolSettingsDlg" Width="370" Height="300" Title="Application Pool Settings - [ProductName]" NoMinimize="yes">
                    <!-- name of the application pool -->
                    <Control Id="PoolNameLabel" Type="Text" X="45" Y="53" Width="100" Height="15" TabSkip="no" Text="&amp;Pool name:" />
                    <Control Id="PoolNameEdit" Type="Edit" X="45" Y="65" Width="220" Height="18" Property="WEB_APP_POOL_NAME" Text="{80}" />
                    
                    <!-- domain -->
                    <Control Id="DomainPoolLabel" Type="Text" X="45" Y="85" Width="100" Height="15" TabSkip="no" Text="&amp;Domain for AppPool:" />
                    <Control Id="DomainPoolEdit" Type="Edit" X="45" Y="97" Width="220" Height="18" Property="WEB_APP_POOL_IDENTITY_DOMAIN" Text="{80}" />
                    
                    <!-- Login -->
                    <Control Id="LoginPoolLabel" Type="Text" X="45" Y="117" Width="100" Height="15" TabSkip="no" Text="&amp;Login for AppPool:" />
                    <Control Id="LoginPoolEdit" Type="Edit" X="45" Y="129" Width="220" Height="18" Property="WEB_APP_POOL_IDENTITY_USERNAME" Text="{80}" />
                    
                    <!-- Password -->
                    <Control Id="PasswordPoolLabel" Type="Text" X="45" Y="149" Width="100" Height="15" TabSkip="no" Text="&amp;Password for AppPool:" />
                    <Control Id="PasswordPoolEdit" Type="Edit" X="45" Y="161" Width="220" Height="18" Property="WEB_APP_POOL_IDENTITY_PWD" Text="{80}" Password="yes" />
                    
                    <!-- Back button -->
                    <Control Id="Back" Type="PushButton" X="180" Y="264" Width="56" Height="17" Text="&amp;Back">
                        <Publish Event="NewDialog" Value="IisSetupDlg">1</Publish>
                    </Control>
                    <Control Id="Next" Type="PushButton" X="236" Y="264" Width="56" Height="17" Default="yes" Text="&amp;Next">
                        <Publish Event="NewDialog" Value="CustomizeDlg">
                            <!--if settings are correct, allow next dialog-->
                            <![CDATA[WEB_APP_POOL_NAME <> "" 
                                     or WEB_APP_POOL_IDENTITY_DOMAIN <> "" 
                                     or WEB_APP_POOL_IDENTITY_USERNAME <> "" 
                                     or WEB_APP_POOL_IDENTITY_PWD <> ""]]>
                        </Publish>
                    </Control>
                    
                    <Control Id="Cancel" Type="PushButton" X="304" Y="264" Width="56" Height="17" Cancel="yes" Text="Cancel">
                        <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
                    </Control>
                    
                    <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="WixUI_Bmp_Banner" />
                    <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes">
                        <Text>Please enter AppPool Configuration for IIS</Text>
                    </Control>
                    
                    <Control Id="BottomLine" Type="Line" X="0" Y="255" Width="370" Height="0" />
                    <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes">
                        <Text>{\WixUI_Font_Title}Application Pool Settings</Text>
                    </Control>
                    
                    <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0" />
                </Dialog>
            </UI>
        </Fragment>
    </Wix>
    

    【讨论】:

    • 这是一个很好的例子,但是需要在 UIFlow.wxs 中删除这些行
    • 我们可以安装 Cassini 并使用 Wiz 在其上部署文件吗?
    • 这不会要求安装用户每次升级产品时都重新提供密码吗?
    • @NineTails 是的,但这是为内部部署过程开发的,通过脚本调用。该脚本为墙面工程师所有,每次调用该脚本时他都会提供密码。
    猜你喜欢
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 2018-01-08
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多