In WiX how can I select an IIS website by name?

前端 未结 5 1811
傲寒
傲寒 2021-01-31 22:31

What I would like to do is show the installer user a list of the websites on their server and allow them to choose one (using the method described here: http://www.cmcrossroads.

5条回答
  •  逝去的感伤
    2021-01-31 22:45

    In my installer I didnt want to create a Web site. I wanted to allow the user to select an existing website. I did this with a custom action in Javascript, and one custom UI panel.


    Custom Action code:

    //
    // CustomActions.js 
    // 
    // Custom Actions usable within WIX For IIS installations.
    // 
    // EnumerateWebSites_CA(): 
    //   Adds new UI to the MSI at runtime to allow the user to select a
    //   website, to which an ISAPI filter will be added.
    // 
    // UpdatePropsWithSelectedWebSite_CA():
    //   fills session with properties for the selected website. 
    //
    // SetAuthProps_CA():
    //   sets properties for the needed user and group that needs authorization to the created dir. 
    //
    // 
    // original idea from: 
    // http://blog.torresdal.net/2008/10/24/WiXAndDTFUsingACustomActionToListAvailableWebSitesOnIIS.aspx
    // 
    // Mon, 23 Nov 2009  10:54
    //
    // 
    // ===================================================================
    
    // http://msdn.microsoft.com/en-us/library/aa372516(VS.85).aspx
    
    var MsiViewModify = 
        {
            Refresh          : 0,
            Insert           : 1,
            Update           : 2,
            Assign           : 3,
            Replace          : 4,
            Merge            : 5,
            Delete           : 6,
            InsertTemporary  : 7,   // cannot permanently modify the MSI during install
            Validate         : 8,
            ValidateNew      : 9,
            ValidateField    : 10,
            ValidateDelete   : 11
        };
    
    
    // http://msdn.microsoft.com/en-us/library/sfw6660x(VS.85).aspx
    var Buttons = 
        {
            OkOnly           : 0,
            OkCancel         : 1,
            AbortRetryIgnore : 2,
            YesNoCancel      : 3
        };
    
    var Icons= 
        {
            Critical         : 16,
            Question         : 32,
            Exclamation      : 48,
            Information      : 64
        }
    
    var MsgKind =
        {
            Error            : 0x01000000,
            Warning          : 0x02000000,
            User             : 0x03000000,
            Log              : 0x04000000
        };
    
    // http://msdn.microsoft.com/en-us/library/aa371254(VS.85).aspx
    var MsiActionStatus = 
        {
            None             : 0,
            Ok               : 1, // success
            Cancel           : 2,
            Abort            : 3,
            Retry            : 4, // aka suspend?
            Ignore           : 5  // skip remaining actions; this is not an error.
        };
    
    //*****************************************************************************
    // Purpose: Custom action that enumerates the local websites, and stores their
    // properties in the ListBox and AvailableWebSites tables.
    // Effects: Fills the ListBox table and creates and fills the AvailableWebSites
    // tables.
    // Returns: MsiActionStatus.Ok  if the custom action executes without error.
    //          MsiActionStatus.Abort if error. 
    //*****************************************************************************
    function EnumerateWebSites_CA()
    {
        try 
        {
            LogMessage("function EnumerateWebSites_CA() ENTER");
    
            var c = 1;
            var serverBindings, aBindings;
    
            var listboxesView = Session.Database.OpenView("SELECT * FROM ListBox");
            listboxesView.Execute();
    
            var record = Session.Installer.CreateRecord(4);
            record.StringData(1) = "WEBSITE";     // Property
            record.IntegerData(2) = c++;          // display order
            record.StringData(3) = "Server";      // returned bby the selection
            record.StringData(4) = "Server-wide"; // displayed in the UI
            listboxesView.Modify(MsiViewModify.InsertTemporary, record);
    
            // Create this table dynamically.  We could also create this
            // custom table in the WiX .wxs file , but that's not necessary.
            //  old quote:  `````` 
            //  my quote:  '''''
    
    //        var createCmd = Session.Database.OpenView("CREATE TABLE 'AvailableWebSites' ('WebSiteNo' INT NOT NULL, 'WebSiteDescription' CHAR(50), 'WebSitePort' CHAR(50) NOT NULL, 'WebSiteIP' CHAR(50), 'WebSiteHeader' CHAR(50) PRIMARY KEY 'WebSiteNo')")
    
            var createCmd = Session.Database.OpenView("CREATE TABLE AvailableWebSites (Num INT NOT NULL, Name CHAR(64), Desc CHAR(64), Port CHAR(16) NOT NULL, IP CHAR(32), Hostname CHAR(80) PRIMARY KEY Num)")
            createCmd.Execute();
            createCmd.Close();
    
            LogMessage("Table 'AvailableWebSites' has been created");
    
            var websitesView = Session.Database.OpenView("SELECT * FROM AvailableWebSites");
            websitesView.Execute();
    
            LogMessage("Query from Table 'AvailableWebSites' has returned");
    
            var iis = GetObject("winmgmts://localhost/root/MicrosoftIISv2"); 
    
            // See the metabase hierarchy diagram here:
            //   http://msdn.microsoft.com/en-us/library/ms524661.aspx
    
            // http://msdn.microsoft.com/en-us/library/ms525545.aspx
            // list "virtual servers", which is the same as websites. 
            var query  = "SELECT * FROM IIsWebServerSetting" 
    
            // get the list of virtual servers
            var results = iis.ExecQuery(query);
    
            LogMessage("WMI Query completed.");
    
            LogMessage("WMI Query results : " + typeof results);
    
            for(var e = new Enumerator(results); !e.atEnd(); e.moveNext()) 
            { 
                var site = e.item();
                // site.Name                   // W3SVC/1, W3SVC/12378398, etc
                // site.Name.substr(6)         // 1, 12378398, etc
                // site.ServerComment)         // "Default Web Site", "Site2", etc
                // site.ServerBindings(0).Port // 80, 8080, etc
    
                LogMessage("Web site " + site.Name);
    
                LogMessage("listbox record");
                record = Session.Installer.CreateRecord(4);
                record.StringData(1) = "WEBSITE";
                record.IntegerData(2) = c++;
                record.StringData(3) = site.Name.substr(6); // site.Name;
                record.StringData(4) = site.ServerComment + " (" + site.Name + ")";
                listboxesView.Modify(MsiViewModify.InsertTemporary, record);
    
                LogMessage("websites record");
                LogMessage("website(" + site.Name + ") name(" + site.ServerComment + ") port(" + site.ServerBindings(0).Port + ")"); 
                record = Session.Installer.CreateRecord(6);
                record.IntegerData(1) = parseInt(site.Name.substr(6));  // WebSiteNo
                record.StringData(2) = site.Name;                       // name, like W3SVC/1
                record.StringData(3) = site.ServerComment;              // WebSiteDescription
                record.StringData(4) = site.ServerBindings(0).Port;     // WebSitePort
                record.StringData(5) = site.ServerBindings(0).Ip;       // WebSiteIP; maybe empty
                record.StringData(6) = site.ServerBindings(0).Hostname; // WebSiteHeader; maybe empty
                websitesView.Modify(MsiViewModify.InsertTemporary, record);
            }
            listboxesView.Close();
            websitesView.Close();
    
            LogMessage("function EnumerateWebSites_CA() EXIT");
        }
    
        catch (exc1)
        {
            Session.Property("CA_EXCEPTION") = exc1.message ;
            LogException(exc1);
            return MsiActionStatus.Abort;
        }
        return MsiActionStatus.Ok;
    }
    
    
    
    //*****************************************************************************
    // Purpose: Custom action that copies the selected website's properties from the
    // AvailableWebSites table to properties.
    // Effects: Fills the WEBSITE_DESCRIPTION, WEBSITE_PORT, WEBSITE_IP, WEBSITE_HEADER
    // properties.
    // Returns: MsiActionStatus.Ok  if the custom action executes without error.
    //          MsiActionStatus.Abort if error. 
    //*****************************************************************************
    function UpdatePropsWithSelectedWebSite_CA()
    {
        try 
        {
            LogMessage("function UpdatePropsWithSelectedWebSite_CA() ENTER");
            var selectedWebSiteId = Session.Property("WEBSITE");
    
            LogMessage("selectedWebSiteId(" + selectedWebSiteId + ") type(" + typeof selectedWebSiteId + ")");
    
            // check if the user selected anything
            if (selectedWebSiteId == "")
            {
                LogMessage("function UpdatePropsWithSelectedWebSite_CA() EXIT (None)");
                return MsiActionStatus.None;
            }
    
            if (selectedWebSiteId.toUpperCase() == "SERVER")
            {
                Session.Property("WEBSITE_NAME")        = "W3SVC";
                Session.Property("WEBSITE_DESCRIPTION") = "Server";
                Session.Property("WEBSITE_PORT")        = "";
                Session.Property("WEBSITE_IP")          = "";
                Session.Property("WEBSITE_HEADER")      = "";
                LogMessage("function UpdatePropsWithSelectedWebSite_CA() EXIT (Ok)");
                return MsiActionStatus.Ok;
            }
    
            var websitesView = Session.Database.OpenView("SELECT * FROM `AvailableWebSites` WHERE `Num`=" + selectedWebSiteId);
            websitesView.Execute();
            var record = websitesView.Fetch();
    
            LogMessage("website Fetch() complete");
    
            if (record.IntegerData(1) == parseInt(selectedWebSiteId))
            {
                Session.Property("WEBSITE_NAME")        = record.StringData(2);
                Session.Property("WEBSITE_DESCRIPTION") = record.StringData(3);
                Session.Property("WEBSITE_PORT")        = record.StringData(4);
                Session.Property("WEBSITE_IP")          = record.StringData(5);
                Session.Property("WEBSITE_HOSTNAME")    = record.StringData(6);
            }
            websitesView.Close();
    
            LogMessage("function UpdatePropsWithSelectedWebSite_CA() EXIT (Ok)");
        }
    
        catch (exc1)
        {
            Session.Property("CA_EXCEPTION") = exc1.message ;
            LogException(exc1);
            return MsiActionStatus.Abort;
        }
        return MsiActionStatus.Ok;
    }
    
    
    // Pop a message box.  also spool a message into the MSI log, if it is enabled. 
    function LogException(exc)
    {
        var record = Session.Installer.CreateRecord(0);
        record.StringData(0) = "IisEnumSites: Exception: 0x" + decimalToHexString(exc.number) + " : " + exc.message;
        Session.Message(MsgKind.Error + Icons.Critical + Buttons.btnOkOnly, record);
    }
    
    
    // spool an informational message into the MSI log, if it is enabled. 
    function LogMessage(msg)
    {
        var record = Session.Installer.CreateRecord(0);
        record.StringData(0) = "IisEnumSites: " + msg;
        Session.Message(MsgKind.Log, record);
    }
    
    
    
    function decimalToHexString(number)
    {
        if (number < 0)
        {
            number = 0xFFFFFFFF + number + 1;
        }    
        return number.toString(16).toUpperCase();
    }
    
    
    // Testing only
    function Test1_CA()
    {
        var record = Session.Installer.CreateRecord(0);
        record.StringData(0) = "Hello, this is an error message";
        Session.Message(msgKindUser + iconInformation + btnOk, record);
        return MsiActionStatus.Ok;
    }
    

    Register the Custom Actions like this:

    
    
      
        
    
        
    
        
    
      
    
    
    

    This is the .wxs for the UI Panel:

    
    
      
        
          
            
            
            
              1
            
            
            
            
            
            
            
            
          
        
      
    
    

    The UI panel presents a listbox, which is automatically populated with elements from the ListBox table with the first field of WEBSITE. This table is populated at runtime by the custom action in Javascript.

    To invoke the custom action at the right time, you need something like this in the main .wxs file:

    
      NOT Installed
    
    

提交回复
热议问题