I’ve been writing this for a while today and couldn’t figure out why I couldn’t get the application to create within IIS. The virtual directory created without problems, but after that nothing happened. It turns out that the msdn library was incorrect!
Here is a working IIS 6 virtual directory creator. The only paramaters that need to be changed are in the // Set comment.
// IIS 6 Virtual Directory Builder and Configuration
// http://r-dunn.co.uk/ieatpenguin/computing/software/962/
// Please feel free to use and distribute
// Set variables: Site_Name,Path_to_wwwroot,Virtual_Directory_Name,Path_to_virtual_dir
// Change the port number after "ServerBindings" if you wish to use a different port.
using System;
using System.IO;
using System.DirectoryServices;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Collections;
namespace System_DirectoryServices_DirectoryEntry_ConfigIIS
{
class Program
{
static void Main(string[] args)
{
CreateSite("IIS://Localhost/W3SVC", "555", "Site_Name", "Path_to_wwwroot");
SetSingleProperty("IIS://Localhost/W3SVC/555", "ServerBindings", ":8080:");
CreateVDir("IIS://Localhost/W3SVC/1/Root", "Virtual_Directory_Name", "Path_to_virtual_dir");
}
static void CreateSite(string metabasePath, string siteID, string siteName, string physicalPath)
{
// metabasePath is of the form "IIS://<servername>/<service>"
// for example "IIS://localhost/W3SVC"
// siteID is of the form "<number>", for example "555"
Console.WriteLine("\nCreating site {0}/{1}, mapping the Root application to {2}:",
metabasePath, siteID, physicalPath);
try
{
DirectoryEntry service = new DirectoryEntry(metabasePath);
string className = service.SchemaClassName.ToString();
if (className.EndsWith("Service"))
{
DirectoryEntries sites = service.Children;
DirectoryEntry newSite = sites.Add(siteID, (className.Replace("Service", "Server")));
newSite.Properties["ServerComment"][0] = siteName;
newSite.CommitChanges();
DirectoryEntry newRoot;
newRoot = newSite.Children.Add("Root", "IIsWebVirtualDir");
newRoot.Properties["Path"][0] = physicalPath;
newRoot.Properties["AccessScript"][0] = true;
newRoot.CommitChanges();
Console.WriteLine(" Done. Your site will not start until you set the ServerBindings or SecureBindings property.");
}
else
Console.WriteLine(" Failed. A site can only be created in a service node.");
}
catch (Exception ex)
{
Console.WriteLine("Failed in CreateSite with the following exception: \n{0}", ex.Message);
}
}
static void SetSingleProperty(string metabasePath, string propertyName, object newValue)
{
// metabasePath is of the form "IIS://<servername>/<path>"
// for example "IIS://localhost/W3SVC/1"
Console.WriteLine("\nSetting single property at {0}/{1} to {2} ({3}):",
metabasePath, propertyName, newValue, newValue.GetType().ToString());
try
{
DirectoryEntry path = new DirectoryEntry(metabasePath);
PropertyValueCollection propValues = path.Properties[propertyName];
string oldType = propValues.Value.GetType().ToString();
string newType = newValue.GetType().ToString();
Console.WriteLine(" Old value of {0} is {1} ({2})", propertyName, propValues.Value, oldType);
if (newType == oldType)
{
path.Properties[propertyName][0] = newValue;
path.CommitChanges();
Console.WriteLine("Done");
}
else
Console.WriteLine(" Failed in SetSingleProperty; type of new value does not match property");
}
catch (Exception ex)
{
if ("HRESULT 0x80005006" == ex.Message)
Console.WriteLine(" Property {0} does not exist at {1}", propertyName, metabasePath);
else
Console.WriteLine("Failed in SetSingleProperty with the following exception: \n{0}", ex.Message);
}
}
static void CreateVDir(string metabasePath, string vDirName, string physicalPath)
{
// metabasePath is of the form "IIS://<servername>/<service>/<siteID>/Root[/<vdir>]"
// for example "IIS://localhost/W3SVC/1/Root"
Console.WriteLine("\nCreating virtual directory {0}/{1}, mapping the Root application to {2}:",
metabasePath, vDirName, physicalPath);
try
{
DirectoryEntry site = new DirectoryEntry(metabasePath);
string className = site.SchemaClassName.ToString();
if ((className.EndsWith("Server")) || (className.EndsWith("VirtualDir")))
{
DirectoryEntries vdirs = site.Children;
DirectoryEntry newVDir = vdirs.Add(vDirName, (className.Replace("Service", "VirtualDir")));
newVDir.Properties["Path"][0] = physicalPath;
newVDir.Properties["AccessScript"][0] = true;
// Create Application, set appropriate documents and permissions
newVDir.Invoke("AppCreate", new object[1] { 1 });
newVDir.Properties["AppFriendlyName"].Value = vDirName;
newVDir.Properties["EnableDirBrowsing"][0] = false;
newVDir.Properties["AccessRead"][0] = true;
newVDir.Properties["AccessExecute"][0] = true;
newVDir.Properties["AccessWrite"][0] = false;
newVDir.Properties["EnableDefaultDoc"][0] = true;
newVDir.Properties["DefaultDoc"][0] = "ReportsIsapi.dll?Login,ReportsIsapi.dll";
newVDir.Properties["AspEnableParentPaths"][0] = true;
newVDir.CommitChanges();
Console.WriteLine(" Done.");
}
else
Console.WriteLine(" Failed. A virtual directory can only be created in a site or virtual directory node.");
}
catch (Exception ex)
{
Console.WriteLine("Failed in CreateVDir with the following exception: \n{0}", ex.Message);
}
}
}
}
Don’t forget to use a double ‘\\’ in your pathnames to avoid the compiler interpreting them as an escape sequence. I certainly did.