wix windows-installer conditional-statements admin msiexec

Instalador de Wix: configuración de la propiedad de condición del componente al realizar una instalación de administrador MSIEXEC en la línea de comandos



windows-installer conditional-statements (3)

Su uso previo al procesador

Estaba a mitad de camino respondiendo con una sugerencia de usar las construcciones de preprocesador ( ?if? Et al) cuando me di cuenta de que solo quería un único MSI (al menos a la vez, al parecer), así que lo omití. Normalmente uso tales construcciones para compilar sabores de archivos MSI de la misma fuente WiX. He descartado lo que escribí a continuación con algunas repeticiones, sin demasiada revisión. Lo comprobaré más tarde.

Puede que me falte algo en su caso, pero no veo cómo y ?if? La declaración puede funcionar en el momento de la instalación: es una construcción en tiempo de compilación . Preprocesa su archivo fuente WiX antes de compilarlo y vincularlo. Como tal , ¿parece que realmente compiló tres versiones diferentes de su archivo MSI y luego ejecutó la instalación administrativa en cada una de ellas? Si este es el caso, entonces el uso de la imagen de administrador es irrelevante, porque todo su MSI no contiene nada más que los componentes con los que ha incluido ?if? - no es necesario pasar ninguna especificación de propiedad de edición.

Configurar sabores

Los enfoques técnicos normales que uso cuando necesito crear diferentes sabores de configuración o ediciones de productos son los siguientes:

  1. Construcciones de preprocesador : se utilizan para compilar diferentes sabores o ediciones (también ediciones en diferentes idiomas) del MSI en tiempo de compilación . Una de esas construcciones es el ?if? declaración que estás mencionando. Hay varios otros, como se ve en el enlace proporcionado directamente arriba. Las más relevantes para usted serían las declaraciones condicionales ( if , ifndef , ifndef , else , elseif , endif ) y posiblemente la declaración include .

    • Por lo tanto, el mensaje general es que las construcciones de preprocesador le permiten construir varios tipos diferentes de archivos MSI a partir de una sola fuente WiX XML .

    • En su caso, esto generaría una única fuente XML de WiX y tres archivos MSI , cada uno para una versión diferente de la aplicación. Todos similares, pero solo con los componentes que necesitan.

    • Ejecutar la instalación a través de /i o la imagen administrativa (extracto de archivo) a través de /a produciría solo los componentes que agregó a esa configuración, pero no tiene un solo MSI como dice, sino tres diferentes dependiendo de cómo compiló.

    • Prefiero usar ?include? declaraciones para incluir archivos de fragmentos WiX en lugar de simplemente condicionar componentes directamente con ?if? como mencionas Hay una muestra de la diferencia en la parte inferior en la sección " Construcciones de preprocesador ".

  2. Funciones de MSI (como respondió PhilDW) : también puede confiar en las funciones de MSI para ofrecer una configuración única en diferentes sabores. Las funciones se utilizan para segregar el MSI en varios elementos de instalación seleccionables por el usuario (algunos de los cuales puede hacer obligatorios).

    • Las características permiten instalar un solo MSI en diferentes sabores , al tiempo que contienen todos los componentes necesarios para cada sabor. Los componentes de acondicionamiento pueden lograr efectos similares.
    • Los componentes de acondicionamiento se asemejan a la manipulación de características, pero funcionan en un nivel más primitivo y fundamental. Estas no son unidades de instalación seleccionables por el usuario, sino partes y piezas fundamentales y atómicas de su producto para instalar y ocultas a la vista del usuario, mientras que las características son seleccionables por el usuario y generalmente visibles para el usuario.
    • El usuario puede ajustar qué funciones se deben instalar o manipular mediante programación mediante una acción personalizada (para anular las especificaciones del usuario y aplicar un diseño técnico de forma automática, por ejemplo).

      • Control de funciones del usuario

        • Los usuarios pueden controlar las funciones para instalar de forma interactiva a través del cuadro de diálogo FeatureTree de la configuración que se encuentra en la mayoría de las configuraciones (no todas). Por lo general, esto implica seleccionar hacer una instalación "personalizada".

        • También puede especificar qué características instalar en la configuración a través de la línea de comandos que inicia la instalación utilizando la propiedad ADDLOCAL y la propiedad REMOVE (y potencialmente otras propiedades similares; consulte el enlace para obtener más detalles).

        • A veces puede establecer una propiedad personalizada durante la instalación que desencadenaría una constelación de características estándar para instalar en función de la "edición" especificada, lo que nos lleva al siguiente punto.

      • Control programático de funciones

        • Agregar un enlace a una respuesta sobre el control de funciones programáticas: ¿Cómo instalar la función en función de la propiedad establecida en la acción personalizada?

        • Como se indicó, puede manipular qué características instalar a través de la línea de comandos utilizando la propiedad ADDLOCAL y la propiedad REMOVE dentro de la configuración mientras se está ejecutando. Para hacer esto, puede usar una acción personalizada .

        • También hay una propiedad INSTALLLEVEL que es relevante para el estado de instalación de las características. Para cada característica hay un nivel de instalación, y puede verse afectado por las condiciones establecidas en la tabla Condición .

          • Por lo tanto, la tabla Condición se puede usar para modificar el estado de selección de cualquier entrada en la tabla Característica en función de una expresión condicional.

          • En otras palabras, puede usar esto para configurar características para instalar o no instalar de forma predeterminada según la condición.

        • Además del concepto INSTALLLEVEL, también puede usar acciones personalizadas para controlar el estado de selección de características.

          • Esto es extrañamente más confiable hoy que la condición de la característica, ya que muchos empaquetadores de aplicaciones maximizan rutinariamente la propiedad INSTALLLEVEL para forzar la instalación de todas las características. Esto es incorrecto ya que es posible que algunas funciones no necesiten instalarse si son incompatibles con el sistema operativo en el que se está ejecutando . He tratado de comunicar esto a muchos oídos sordos.
        • Usando estas construcciones programáticas, su configuración puede, por ejemplo, cambiar el estado de selección de características para lo que se instalará en función de una clave serial ingresada por el usuario.

        • Su configuración también puede determinar que una determinada característica no debe instalarse en función del sistema operativo que esté ejecutando (por ejemplo, no instale las características de Tablet OS ).

        • Podría haber cualquier cantidad de razones técnicas y prácticas para cambiar la selección de funciones mediante programación.

    • Es importante tener en cuenta que el resultado general es que la selección de funciones se puede establecer a través de la línea de comando o por el usuario, y luego su configuración realiza algunas modificaciones "ocultas" por razones técnicas.

    • Y solo para señalarlo: las características que se manipulan para la instalación mediante programación generalmente se ocultan de la vista (pero aún es posible anularlas a través de la línea de comandos, lo que puede ser un problema).

    • Más información sobre características, componentes y personalización de configuraciones para la instalación aquí: Cómo hacer un mejor uso de los archivos MSI .

  3. Iniciador de Setup.exe : una forma "moderna" de realizar una implementación compleja en diferentes versiones puede ser usar la función Grabar de WiX para compilar configuraciones MSI más pequeñas que se instalan en diferentes "conjuntos" para producir un estado de instalación diferente.

    • Considero que esto es demasiado complicado para uso general, pero ciertamente es posible. Creo que algunos lo encuentran más fácil, ya que hay menos manipulación de características. Tal vez solo me falta experiencia con eso.
    • El beneficio es que los archivos MSI más pequeños se instalan más rápido, y puede actualizar un solo archivo MSI y crear un nuevo contenedor setup.exe y luego realizar un control de calidad total en toda su solución sin reconstruir todas las configuraciones.
    • En mi mundo, un MSI único y actualizado requiere un control de calidad completo de todos modos, por lo que no siempre compro estos "argumentos de simplicidad". Cada ciclo de lanzamiento tiene riesgos y, por lo tanto, aumenta el riesgo total . Sin embargo, puede ser genial poder reconstruir una configuración pequeña y mantener estable la grande.

Uso práctico

Prefiero hacer la menor cantidad posible de configuraciones , pero la mayoría de las veces termino usando construcciones de preprocesador para crear diferentes configuraciones para diferentes versiones de idiomas (inglés, alemán, ruso) y también para diferentes ediciones de productos (Enterprise, Professional, Standard) . Por lo general, los configuro todos relacionados compartiendo un código de actualización y no son capaces de instalar uno al lado del otro.

Siento que un solo MSI obtiene más recursos de control de calidad y, por lo tanto, se probará mejor. Sin embargo, este enfoque único de MSI generalmente se rompe si las configuraciones son muy grandes, en cuyo caso me gustaría dividirlas. También me gusta hacer configuraciones separadas para cada idioma por razones prácticas comerciales y del mundo real explicadas aquí . Los requisitos prácticos y legales (licencias) también pueden hacer que sea imperativo compilar versiones especiales de la misma configuración de MSI. También se me ha pedido que cree nuevos sabores MSI para proveedores OEM .

Y ahora una conclusión sorprendente (que nunca solicitó :-)): con todo lo dicho, en un mundo ideal me gusta instalar todas las funciones sin ningún problema técnico en la configuración, y usar la clave de serie para determinar qué funcionalidad de la aplicación y Los módulos deben activarse en la aplicación. También me gusta poner la validación de la clave de serie dentro de la aplicación, y tampoco en la configuración. El motivo ? Quiero configuraciones tan primitivas como sea posible para garantizar que la aplicación se instale correctamente sin un alto porcentaje de error de implementación. Por lo tanto, busco la complejidad para matar en la implementación para garantizar menos problemas de soporte de implementación. La implementación confiable es crucial para el éxito del producto . Una vez que esté instalado, su aplicación puede iniciarse en un contexto mucho más depurable y predecible (sin problemas de condicionamiento, suplantación o secuenciación) e informar cualquier error de manera interactiva y significativa al usuario, y pueden llamar al soporte con más esperanza de resolver con éxito cualquier problema de lo que sería el caso si la configuración acabara bombardeada con un misterioso mensaje de error no interactivo (en el registro de eventos del sistema).

Una vez que obtenga una solución de implementación buena y simple, su trabajo como administrador de versiones y desarrollador de configuración debe expandirse para encargarse de la secuencia de inicio de la aplicación, la configuración de archivos y la configuración general y también, en mi opinión, las funciones de soporte y depuración que desee agregar a la aplicación (autoinspección de la aplicación y registro y recopilación automática de información para enviar a soporte). Intente expandir su responsabilidad e influencia con la aplicación misma para mantener la implementación "lo más primitiva posible". Cualquier cosa que pueda codificarse en la aplicación en lugar de en la configuración será más confiable a largo plazo (y mucho más fácil de depurar).

De vuelta a la realidad : para una implementación real, recibirá un montón de archivos con un esquema de versiones irregulares que se le entregará a través de un recurso compartido de red lento con un montón de instrucciones incoherentes de un desarrollador que está en el extranjero y paga por hora (puede estar seguro de que siente el dolor también :-) ). Y tendrán un montón de requisitos parcialmente locos para que su configuración haga magia para cubrir su diseño menos que ideal (que es todo lo que se les pagó para hacer). Esto no es una queja, es una realidad, es triste decirlo ( OK, es una queja ). Debemos trabajar para mejorar el diseño general de una aplicación para que la implementación sea menos propensa a errores. De hecho, la magia se puede hacer en una configuración, pero generará porcentajes de error más altos para la implementación debido a la complejidad inevitable e indisciplinada de la implementación (lo más significativo: 1) errores son acumulativos: cada versión agrega riesgos y oportunidades para romper la capacidad de servicio de su instalación (a veces tiene que retirar todo y comenzar de nuevo, a un gran costo), 2) los sistemas de destino se encuentran en estados extremadamente diversos e impredecibles (cualquier estado, cualquier idioma, cualquier edición del sistema operativo, cualquier hardware, cualquier malware, etc.) , 3) depuración es muy difícil cuando no tiene acceso a los sistemas problemáticos de forma interactiva; consulte la parte inferior de la respuesta vinculada para obtener más detalles. Y agregaré un 4th issue cae del segundo: ¿ puede garantizar la implementación en una máquina repleta de malware? Dichos sistemas son imposibles de soportar y depurar; simplemente elija para encontrar un problema crítico que no pueda solucionar. Si su paquete falla en dichos sistemas de malware, es un porcentaje de error natural que es inevitable .

El punto general es obvio: no podemos dar cuenta de estas incógnitas: basura, basura (con disculpas por cómo suena eso), habrá un porcentaje de error, cada vez que implemente, incluso para paquetes perfectos . Asegúrese de tomar todos los QA-guys disponibles y siempre valiosos y enséñeles sobre las pruebas de configuración (prueba de todos los modos de instalación, prueba de desinstalación e interacción con otras aplicaciones, prueba de escenarios de actualización del mundo real, prueba de características de configuración avanzadas específicas como verificación de licencias, etc. ...) Obtenga toda la ayuda que pueda obtener y valore sus contribuciones. Si nada más, como cómplices :-). En serio: no utilizar los recursos de control de calidad disponibles de manera efectiva y ayudarlos a capacitarlos en las pruebas de implementación es uno de mis principales descuidos como administrador de versiones y desarrollador de configuraciones. Es una suposición segura que les deberás a tus muchachos de QA una botella de Horílka en poco tiempo, o té verde o té Rooibos, dependiendo de dónde estés en el mundo :-).

Construcciones de preprocesador

Probablemente usaría las construcciones de preprocesador ?if? y ?include? para incluir selectivamente diferentes secciones del código fuente / marcado XML WiX basado en su edición definida en el ?define? declaración en la parte superior de la muestra:

<?define EditionType = “LITE” ?> <!-- You can put your edition-specific components in an include file --> <?if $(var.EditionType) = "200" ?> <?include "200Features.wxi" ?> <?endif ?> <?if $(var.EditionType) = "LITE" ?> <?include "LiteFeatures.wxi" ?> <?endif ?>

En lugar de usar archivos de inclusión, también puede hacer esto en línea en su fuente principal (esto podría ser lo que ha hecho):

<?if $(var.EditionType) = "200" ?> <Component> <File Source="$(var.MenusPath)/ClientListView 200.r5m" /> </Component> <?endif?> <?if $(var.EditionType) = "LITE" ?> <Component> <File Source="$(var.MenusPath)/ClientListView Lite.r5m" /> </Component> <?endif?>

De las opciones anteriores, preferiría mantener los componentes específicos de la edición en un archivo de inclusión separado (primera opción), luego hay menos "ruido de línea" en su fuente WiX (menos repeticiones de las construcciones del preprocesador).

Los archivos de inclusión son básicamente archivos WiX XML que se incluyen como los archivos de encabezado C ++ en el archivo XML WiX padre en tiempo de compilación. Como Phil dice, usaría diferentes nombres de características para las diferentes ediciones, por lo que define una característica 200Features en el archivo de inclusión 200Features.wxi, pero no necesita usar características, aunque se recomienda encarecidamente.

También tenga en cuenta el concepto WiX del elemento fragmento . Esencialmente, una forma de hacer referencias cruzadas de contenido en el archivo fuente de WiX. Un ejemplo aquí .

Debo mencionar que el concepto original de módulos de fusión en MSI proporciona una forma diferente de compartir componentes entre diferentes configuraciones, pero me gusta más el enfoque de incluir archivo. Los módulos de fusión se sienten como objetos COM de alguna manera (blob binario incluido como un todo versionado), mientras que los archivos de inclusión parecen más dinámicos en el sentido de que obtienes los últimos archivos vinculados para cada compilación sin ninguna reconstrucción y versión del módulo de fusión. Indudablemente, algunas personas encontrarán esto muy mal.

Tenemos tres tipos / sabores de nuestro producto, pero solo un MSI escrito en WiX. Cuando construimos el instalador, pasamos el sabor a través de una constante definida:

Call MSBUILD.bat ../MSIs/CoreProduct/OurProduct.sln /p:DefineConstants="FLAVOUR=%_Flavour%"

y la constante se configura en Visual Studio, en Build -> Definir variables de preprocesador como FLAVOR = 50. El proceso de construcción, pasa en valores 50, 200 o LITE como el sabor.

En el código WiX tenemos un montón de condiciones en nuestros componentes que le indican qué archivo instalar en función del sabor; p.ej

<Component Id="cmp7F45920B1AA100729BAE37FC846B3FC5" Guid="*"> <File Id="fil238A776D9294E14671E012472F9F7196" KeyPath="yes" Source="$(var.MenusPath)/ClientListView 200.r5m" <Condition>$(var.FLAVOUR)=200</Condition> </Component> <Component Id="cmp8BFF42B232724DC4BA5B8F87994DEF21" Guid="*"> <File Id="fil808D6428D67248DDB8CA65DBC5978283" KeyPath="yes" Source="$(var.MenusPath)/ClientListView Lite.r5m" <Condition>$(var.FLAVOUR)=LITE</Condition> </Component>

Entonces, el ejemplo anterior instalará un archivo llamado "ClientListView Lite.r5m" si el FLAVOR es LITE o instalará un archivo llamado "ClientListView 200.r5m" si el FLAVOR es 200.

¡Todo esto funciona como se esperaba y lo ha hecho durante años!

Pero ahora, tenemos una versión web de nuestro producto y necesitamos un archivo zip que contenga la estructura de carpetas y los archivos que se instalarían para cada versión. Descubrí que puedes ejecutar un msi en la línea de comando usando MSIEXEC y el argumento / a que luego redirigirá todo lo que se habría instalado en una carpeta y pensé que esto es exactamente lo que quiero ... pero, por desgracia, no funciona como yo Había esperado.

Lo que parece estar haciendo es ejecutar el MSI y extraer los archivos en la carpeta de destino, pero está ignorando el sabor y, por lo tanto, terminas con los archivos "ClientListView Lite.r5m" y "ClientListView 200.r5m" extraídos en la carpeta; que obviamente no es lo que quiero.

Al leer los documentos en MSIEXEC, parece que puede pasar el valor de una propiedad pública, por ejemplo msiexec.exe / a "C: / Example.msi" MY_PROP = "myValue", por lo que pensé que esto podría ayudarme; así que en mi código WiX agregué la línea:

<Property Id=''PRODTYPE'' Value="$(var.FLAVOUR)"/>

y luego alteré las condiciones de mi componente para que sea así:

<Component Id="cmp7F45920B1AA100729BAE37FC846B3FC5" Guid="*"> <File Id="fil238A776D9294E14671E012472F9F7196" KeyPath="yes" Source="$(var.MenusPath)/ClientListView 200.r5m" <Condition><![CDATA[PRODTYPE=200]]></Condition> </Component> <Component Id="cmp8BFF42B232724DC4BA5B8F87994DEF21" Guid="*"> <File Id="fil808D6428D67248DDB8CA65DBC5978283" KeyPath="yes" Source="$(var.MenusPath)/ClientListView Lite.r5m" <Condition><![CDATA[PRODTYPE=LITE]]></Condition> </Component>

pero aunque eso compiló bien, ejecutándolo a través de:

msiexec /a OurProduct.msi /qb PRODTYPE=200 TARGETDIR="C:/InstalledFiles200"

todavía extrae ambos archivos para los sabores 200 y LITE, donde solo quería el de 200.

Entonces, estoy tratando de hacer algo que no es posible ... o estoy haciendo algo mal, agradecería cualquier ayuda, porque la alternativa de imitar el proceso en un archivo por lotes para crear mi zip; será horrible !!

Aclamaciones,

Chris


El modificador / a en la línea de comando msiexec no es una instalación en el sentido habitual. Literalmente es solo un desempaquetado de los archivos en una ubicación. Si desea una instalación real, debe usar / i o simplemente hacer doble clic en el archivo MSI. Eso le dará una instalación completa adecuada con una entrada en Programas y características, etc.

Las opciones de qué instalar se manejan más normalmente dividiendo la configuración en características, cada una con un conjunto de componentes que contienen la funcionalidad requerida. En la interfaz de usuario de WiX, puede obtener un cuadro de diálogo para elegir las funciones, y el modo de mantenimiento le permitirá volver y cambiarlas. En una instalación de línea de comandos, simplemente diría / i [archivo msi] ADDLOCAL = Feature1, Feature2, etc. Si realmente quieres usar "sabor", internamente lo convertirías en una lista ADDLOCAL.


Gracias por la información, pero creo que entendiste mal lo que estaba tratando de lograr; No quiero ejecutar el instalador a través de / i porque, como dijiste, eso realmente instalaría los archivos y cambiaría el registro, etc. Lo que quería hacer era ejecutar el instalador dos veces: una para el sabor 200 y otra vez para el sabor Lite; así que terminaría con dos carpetas que contienen los archivos que "se instalarían" si lo ejecutara con / i. Obviamente no puedo ejecutarlo dos veces con / i, porque la segunda vez que lo ejecute, desinstalará el primero.

De todos modos, descubrí que las condiciones dentro de los componentes se ignoran durante una "instalación" del administrador, mientras que? Si? las declaraciones no se ignoran, no estoy seguro de por qué, pero ahora eliminé todas mis declaraciones de condición y las reemplacé con declaraciones IF, así que ahora puedo hacer lo que quería hacer: ejecútelo dos veces con / ay cada carpeta contendrá los archivos únicos a ese sabor.