2009-08-28 10 views
12

Was ich tun möchte ist, zeigen Sie dem Installer Benutzer eine Liste der Websites auf ihrem Server und erlauben Sie ihnen, eine zu wählen (mit der hier beschriebenen Methode: http://www.cmcrossroads.com/content/view/13160/120/, die jetzt scheint gebrochen siehe here für den Kern-Code). Das Installationsprogramm erstellt dann auf der ausgewählten Website ein virtuelles Verzeichnis.In WiX Wie kann ich eine IIS-Website namentlich auswählen?

Meine Suche scheint jedoch ergeben zu haben, dass die einzige Möglichkeit, eine Website in WiX anzugeben, IP, Port und Header ist. Nach diesen Fragen zu fragen, ist nicht sehr benutzerfreundlich, daher bleibt mir die Idee, eine zweite benutzerdefinierte Aktion zu schreiben, um diese Details von einem Website-Namen zu erhalten.

Gibt es einen besseren Weg?

BTW Dies muss sowohl in IIS6 als auch in IIS7 funktionieren, falls sich dies auf die Antwort auswirkt.

Antwort

9

OK es ist möglich (in IIS6 oder IIS7 mit Metabase-Kompatibilität), dank this Beitrag an die Mailingliste, die die etwas bizarre Art und Weise erklärt die Website: Element funktioniert. Der nützliche Teil ist:

Using a fragment like this and test with v3.0.5120.0:* 

    <iis:WebSite Id="WebSite" Description="Default Web Site" SiteId="*"> 
    <iis:WebAddress Id="TestWebSite" Port="1" /> 
    </iis:WebSite> 

The following work: 

1. If WebSite/@SiteId="*" then a case sensitive match on WebSite/@Description happens. 
2. If WebSite/@SiteId matches the site id than WebSite/@Description is ignored and a match on site id happens. 
3. If WebSite/@SiteId has any value WebAddress/@Port is ignored (although the syntax requires it and it can't be 0). 
4. If WebSite/@SiteId is missing WebAddress/@Port is used and WebSite/@Description is ignored. 
5. Once a website is created and gets site id, you can rename it (therefore its site id is not the hash of its name), the WebSite/@SiteId="*" syntax will match on the WebSite/@Description. 

Also mein WiX Code endet aussehen wie:

<DirectoryRef Id="TARGETDIR"> 
    <Component Id="IisSetup" Guid="YOUR-GUID-HERE"> 
    <iis:WebVirtualDir Id="IisVirtualDir" Alias="[IIS_VIRTUALDIRNAME]" Directory="INSTALLLOCATION" WebSite="IisWebsite"> 
     <iis:WebApplication Id="IisWebApplication" Name="[IIS_VIRTUALDIRNAME]" WebAppPool="IisAppPool" Isolation="high"/> 
    </iis:WebVirtualDir> 
    <iis:WebAppPool Id="IisAppPool" Name="[IIS_APPPOOLNAME]" Identity="networkService"/> 
    </Component> 
</DirectoryRef> 

<!-- Note that this entry should not be put under a component. If it is WiX 
    will update the website on install and remove it on uninstall --> 
<iis:WebSite Id="IisWebsite" Description="[IIS_WEBSITENAME]" SiteId="*"> 
    <iis:WebAddress Id="IisWebAddress" Port="80" /> 
</iis:WebSite> 

Die iis: webaddress Element sollte niemals verwendet werden, aber notwendig für das Projekt zu kompilieren.

0

Während diese Frage und Antwort noch gültig sind, denke ich, es lohnt sich zu fragen, ob Sie wirklich den Namen der Website verwenden möchten. Wenn Sie es für die Verwendung während der Deinstallation speichern möchten, ist das Speichern der Website-ID wahrscheinlich eine bessere Idee. In diesem Fall wird das Website-Element:

<iis:WebSite Id="IisWebsite" Description="Dummy" SiteId="[IIS_WEBSITEID]"> 
    <iis:WebAddress Id="IisWebAddress" Port="80" /> 
</iis:WebSite> 
3

In meinem Installer wollte ich keine Website erstellen. Ich wollte dem Benutzer erlauben, eine existierende Webseite auszuwählen. Ich tat dies mit einer benutzerdefinierten Aktion in Javascript und einem benutzerdefinierten UI-Bereich.


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; 
} 

die benutzerdefinierten Aktionen wie diese registrieren:

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> 

    <Fragment> 
    <Binary Id="IisScript_CA" SourceFile="CustomActions.js" /> 

    <CustomAction Id="EnumerateWebSites" 
        BinaryKey="IisScript_CA" 
        JScriptCall="EnumerateWebSites_CA" 
        Execute="immediate" 
        Return="check" /> 

    <CustomAction Id="UpdatePropsWithSelectedWebSite" 
        BinaryKey="IisScript_CA" 
        JScriptCall="UpdatePropsWithSelectedWebSite_CA" 
        Execute="immediate" 
        Return="check" /> 

    </Fragment> 

</Wix> 

Dies ist die .wxs für den UI-Panel:

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> 

    <Fragment> 
    <UI> 
     <Dialog Id="SelectWebSiteDlg" Width="370" Height="270" Title="Select a Web Site"> 
     <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="Next" /> 
     <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="Back" /> 
     <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="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Please select which web site you want to install to." /> 
     <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="Select a Web Site" /> 
     <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="SelectWebSiteLabel" Type="Text" X="20" Y="60" Width="290" Height="14" NoPrefix="yes" Text="Select the web site for the filter:" /> 
     <Control Id="SelectWebSiteCombo" Type="ListBox" X="20" Y="75" Width="200" Height="150" Property="WEBSITE" Sorted="yes" /> 
     </Dialog> 
    </UI> 
    </Fragment> 
</Wix> 

Der UI-Panel stellt eine List-Box, die automatisch mit den Elementen aus der List-Box-Tabelle mit dem ersten Bereich der Website-füllt wird. Diese Tabelle wird zur Laufzeit von der benutzerdefinierten Aktion in Javascript gefüllt.

Um die benutzerdefinierte Aktion zur richtigen Zeit aufzurufen, benötigen Sie im Wesentlichen so etwas.wxs Datei:

<InstallUISequence> 
    <Custom Action="EnumerateWebSites" After="CostFinalize" Overridable="yes">NOT Installed</Custom> 
</InstallUISequence> 
+0

Eine Idee, warum das obige Skript würde eine "IisEnumSites: Ausnahme: 0x80004005: Ändern, Modus, Record" Fehlermeldung? – Aaron

+0

ah, nein, ich habe keine Ahnung. – Cheeso

0

Antworten auf Für IisEnumSites:Exception: 0x80004005 : Modify, Mode, Record

ich ähnliche Erfahrungen haben und was ich gefunden habe ist bisher die Site-ID, die von parseInt extrahieren:

record = Session.Installer.CreateRecord(6); 
record.IntegerData(1) = parseInt(site.Name.substr(6)); // WebSiteNo 

ich mit einem über eine Website Name wie W3SVC/1528550093 und ich vermute, 1528550093 ist zu groß für die Tabelle AvailableWebSites.

Sobald ich die if-Anweisung haben, diese große Zahl herauszufiltern, und das Skript funktioniert gut.

Hoffe diese Hilfe für andere.

Verwandte Themen