Update 30th July 2009: After deploying this to a development server there were a few tweaks I needed to make to get it working. I have amended the post as necessary.
I needed to be able to create a virtual directory in IIS via my ASP.NET application. I found this nice little example in VB.NET and converted it to C#. You need to add a reference to System.DirectoryServices to use it. The VB.NET example always puts the new virtual directory in the default website, so I have amended it to allow choosing the server and website you want to place the virtual directory under.
private void CreateVirtualDir(string serverName, string website, string appName, string path) { DirectoryEntry IISSchema = new DirectoryEntry(string.Concat("IIS://", serverName, "/Schema/AppIsolated")); bool canCreate = IISSchema.Properties["Syntax"].Value.ToString().ToUpper() != "BOOLEAN"; IISSchema.Dispose(); //get the identifier for the site we want int identifier = 0; DirectoryEntry root = new DirectoryEntry(string.Concat("IIS://", serverName, "/W3SVC")); foreach(DirectoryEntry de in root.Children) { if (de.SchemaClassName.ToUpper().Equals("IISWEBSERVER") && de.Invoke("Get", "ServerComment").ToString().ToUpper().Equals(website.ToUpper())) { identifier = Convert.ToInt32(de.Name); break; } } if (canCreate && identifier > 0) { bool pathCreated = false; try { DirectoryEntry iisAdmin = new DirectoryEntry(string.Format("IIS://{0}/W3SVC/{1}/Root", serverName, identifier)); //make sure folder exists if (!System.IO.Directory.Exists(path)) { System.IO.Directory.CreateDirectory(path); pathCreated = true; } //If the virtual directory already exists then delete it foreach (DirectoryEntry vd in iisAdmin.Children) { if (vd.Name.Equals(appName)) { iisAdmin.Invoke("Delete", new string[] { vd.SchemaClassName, appName }); iisAdmin.CommitChanges(); break; } } //Create and setup new virtual directory DirectoryEntry vDir = iisAdmin.Children.Add(appName, "IIsWebVirtualDir"); vDir.Properties["Path"][0] = path; vDir.Properties["AppFriendlyName"][0] = appName; vDir.Properties["EnableDirBrowsing"][0] = false; vDir.Properties["AccessRead"][0] = true; vDir.Properties["AccessExecute"][0] = true; vDir.Properties["AccessWrite"][0] = false; vDir.Properties["AccessScript"][0] = true; vDir.Properties["AuthNTLM"][0] = true; vDir.Properties["EnableDefaultDoc"][0] = true; vDir.Properties["DefaultDoc"][0] = "default.htm,default.aspx,default.asp"; vDir.Properties["AspEnableParentPaths"][0] = true; vDir.CommitChanges(); //the following are acceptable params //INPROC = 0 //OUTPROC = 1 //POOLED = 2 vDir.Invoke("AppCreate", 1); } catch (Exception ex) { if (pathCreated) { System.IO.Directory.Delete(path); } throw ex; } } else { throw new ApplicationException("Failed to create Virtual Directory"); } }
To create a new virtual directory I can then call the method like this:
try { CreateVirtualDir("localhost", "MyWebSite" "MyVirtualDirectory", @"c:\sites\mysite"); } catch (Exception ex) { lblMessage.Text = string.Concat("An error occurred: ", ex.Message); }
When I deployed this to a development server I got an ‘Access is denied’ error on this following line:
vDir.CommitChanges();
This is because IIS administration need to be done by a user in the administrator group which is the ASPNET user is not. To resolve this I created a new window user on the server which was a member of the administrator group. I then added the following to my Web.config:
<system.web> <identity impersonate="true" userName="username" password="password" /> </system.web>
You could also wrap this in an pages element to restrict which pages will impersonate this identity.