Search code examples
wixcustom-action

Custom Action Won't Run in WIX Installer


I am attempting to create an MSI, who's sole purpose is to install the 'Microsoft Root Certificate Authority 2011' certificate on a Windows 7 machine before running the .NET Framework installer as part of a WIX boostrapper. As I have not found another way to install this certificate from the bootstrapper before the .NET 4.8 installation, I decided to create an MSI that included a custom action to install the certificate, then add it to the chain to the MSIPackage call. I'm testing the installer separately right now. So, basically I've built the custom action, and added it to the WIX setup project. However, after building, when I run the msi, the cert is not installed. I have added a file to be created, as part of the custom action, just to see if it's running, but the file is never created either.

My custom action is as follows:

[CustomAction]
        public static ActionResult CheckForExistingCertificate(Session session)
        {
            session.Log("Starting CheckForExistingCertificate");

            var logFile = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) +
                          @"\CertificateInstallInfo";

            if (!File.Exists(logFile))
                File.Create(logFile);

            try
            {
                session.Log("***** Beginning LocalMachine Certificate Store Search...");
                X509Store lmStore = new X509Store(StoreName.CertificateAuthority, 
StoreLocation.LocalMachine);
                lmStore.Open(OpenFlags.ReadOnly);
                session.Log("***** lmStore.Certificates.Count = " + lmStore.Certificates.Count);
                foreach (X509Certificate2 cert in lmStore.Certificates)
                {
                    session.Log("lmCertificate Listing : " + cert.FriendlyName);
                    if (cert.FriendlyName == "Microsoft Root Certificate Authority 2011")
                    {
                        session["INTERMEDIATECERTIFICATEALREADYINSTALLED"] = "TRUE";
                    }
                }

                session.Log("***** Beginning CurrentUser Certificate Store Search...");
                X509Store cuStore = new X509Store(StoreName.CertificateAuthority, StoreLocation.CurrentUser);
                cuStore.Open(OpenFlags.ReadOnly);
                session.Log("***** cuStore.Certificates.Count = " + cuStore.Certificates.Count);
                foreach (X509Certificate2 cert in cuStore.Certificates)
                {
                    session.Log("cuCertificate Listing : " + cert.FriendlyName);
                    if (cert.FriendlyName == "Microsoft Root Certificate Authority 2011")
                    {
                        session["INTERMEDIATECERTIFICATEALREADYINSTALLED"] = "TRUE";
                    }
                }

                if (session["INTERMEDIATECERTIFICATEALREADYINSTALLED"] == "FALSE")
                {
                    X509Certificate2 certificate = new X509Certificate2("MicrosoftRootCertificateAuthority2011.cer");
                    X509Store store = new X509Store(StoreName.Root, StoreLocation.LocalMachine);

                    store.Open(OpenFlags.ReadWrite);
                    store.Add(certificate);
                    store.Close();
                }

            }
            catch (Exception ex)
            {
                File.WriteAllText(logFile, ex.ToString());
                session.Log("CheckForExistingCertificate - in catch");
            }

            session.Log("Ending CheckForExistingCertificate - end of function");
            return ActionResult.Success;
        }

And my WIX setup Product.wxs file is:

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
    <Product Id="*" Name="Install Certificates" Language="1033" Version="1.0.0.0" Manufacturer="Just Joe Applications" UpgradeCode="68d00e98-21a2-480f-bb3a-be3049995f3c">
        <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />

        <!--<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />-->
        <MediaTemplate />

        <Binary Id="CustomActionBinary" SourceFile="$(var.InstallCertificateAction.TargetDir)$(var.InstallCertificateAction.TargetName).CA.dll" />
        <CustomAction Id="InstallCert" Impersonate="no" BinaryKey="CustomActionBinary" DllEntry="CheckForExistingCertificate" Execute="deferred" Return="check" />

        <InstallExecuteSequence>
            <Custom Action="InstallCert" After="InstallInitialize"/>
        </InstallExecuteSequence>

        <Feature Id="ProductFeature" Title="Install Certificates" Level="1">
            <ComponentGroupRef Id="ProductComponents" />
        </Feature>
    </Product>

    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="INSTALLFOLDER" Name="Install Certificates" />
            </Directory>
        </Directory>
    </Fragment>

    <Fragment>
        <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
        </ComponentGroup>
    </Fragment>
</Wix>

Solution

  • If you want to do this as an MSI Package in your bootstrapper bundle, just use the WiX IIS Extension to install the certificate(s) into the proper certificate store.

    If I was going to do this using my own code, I would just author it as a windowless console application and wire it up to the bootstrapper as an EXE Package. You could write a registry value to use in a detect condition also but if you don't bother it's probably not harmful to run the program over and over.