Thought Id post the code for a custom action that allows WIX to install a virtual directory under the defualt website no matter what IP/Port/Header the default website is using. If the default website is not using defaults (port 80, no header, different IP Address) then Wix will choke without using a custom action. This is not documented at all and finding any solutions to do just this is non existant.
Note that in the Wix file you will be writing these values to the registry. This is so you can uninstall the site. Without storing these values in the Registry there would be zero way to uninstall your application.
using System;using System.DirectoryServices;using Microsoft.Deployment.WindowsInstaller;namespace IISCustomAction{ public class CustomActions { [CustomAction] public static ActionResult GetWebSites(Session session) { try { DirectoryEntry iisRoot = new DirectoryEntry("IIS://localhost/W3SVC"); foreach (DirectoryEntry webSite in iisRoot.Children) { if (webSite.SchemaClassName.ToLower() == "iiswebserver" && webSite.Name.ToLower() != "administration web site") { if (webSite.Properties["ServerComment"].Value.ToString() == "Default Web Site" ) { string[] serverBindings = ((string)webSite.Properties["ServerBindings"].Value).Split(':'); session["WEBSITE_IP"] = serverBindings[0]; session["WEBSITE_PORT"] = serverBindings[1]; session["WEBSITE_HEADER"] = serverBindings[2]; } } } } catch (Exception ex) { session.Log("CustomActionException: " + ex.ToString()); return ActionResult.Failure; } return ActionResult.Success; } }}
\\Other stuff<Component Id="PersistWebSiteValues" Guid=""> <RegistryKey Root="HKLM" Key="Software\Company\[ProductName]"> <RegistryValue Name="WebsiteIP" Value="[WEBSITE_IP]" Type="string"/> <RegistryValue Name="WebsitePort" Value="[WEBSITE_PORT]" Type="string"/> <RegistryValue Name="WebsiteHeader" Value="[WEBSITE_HEADER]" Type="string"/> </RegistryKey> </Component>\\other stuff<InstallUISequence> <Custom Action="GetIISWebSites" After="CostFinalize" Overridable="yes" /> </InstallUISequence> <CustomAction Id="GetIISWebSites" BinaryKey="IISCA" DllEntry="GetWebSites" Execute="immediate" Return="check" /> <Binary Id="IISCA" SourceFile="C:\Documents and Settings\Administrator\My Documents\Visual Studio 2008\Projects\IISCustomAction\bin\Debug\IISCustomAction.CA.dll" /> <Property Id="WEBSITE_IP"> <RegistrySearch Id="WebsiteIP" Root="HKLM" Type="raw" Name="WebsiteIP" Key="Software\Company\[ProductName]"/> </Property> <Property Id="WEBSITE_PORT"> <RegistrySearch Id="WebsitePort" Root="HKLM" Type="raw" Name="WebsitePort" Key="Software\Company\[ProductName]"/> </Property> <Property Id="WEBSITE_HEADER"> <RegistrySearch Id="WebsiteHeader" Root="HKLM" Type="raw" Name="WebsiteHeader" Key="Software\Company\[ProductName]"/> </Property>
Thanks for sharing. I am actually looking into doing more IIS to report health info over some webservice for clients. How to engage custom actions from WIX will come in handy.
Just to note that code will fail if not using an English version of WHS. I will post some updated code later that is language independent.
Hey snowdins did you ever patch the code so that it works on non English WHS? Wondering whether or not I should create my installer in WIX or the use the Visual Studio Setup MSI program?
thanks
I've changed the code to the below and it works great for any langauge and any iis setting now.
using System;using System.DirectoryServices;using Microsoft.Deployment.WindowsInstaller;using System.Collections;using System.ComponentModel;using System.Windows.Forms;namespace IISCustomAction{ public class CustomActions { [CustomAction] public static ActionResult GetWebSites(Session session) { try { DirectoryEntry entry = new DirectoryEntry("IIS://localhost/w3svc/1"); PropertyValueCollection pvc = entry.Properties["ServerBindings"]; foreach (object value in pvc) { // Format is IPAddress:Port:HostHeader string[] Bits = value.ToString().Split(':'); session["WEBSITE_IP"] = Bits[0]; session["WEBSITE_PORT"] = Bits[1]; session["WEBSITE_HEADER"] = Bits[2]; } } catch (Exception ex) { MessageBox.Show(ex.ToString() + ex.StackTrace.ToString() + ex.Data.ToString()); //session.Log("CustomActionException: " + ex.ToString()); return ActionResult.Failure; } return ActionResult.Success; } }}
You'd also need to change the <InstallUISequence> section so that it runs as an Add-In as UI's are not used.
<InstallExecuteSequence>
<Custom Action="GetIISWebSites" Overridable="no" After="CostFinalize" />
</InstallExecuteSequence>