Click here to Skip to main content
Click here to Skip to main content

WMI Functions from ASP.NET

, 10 Feb 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Add a website, virtual folder, and host header to IIS 6 from code.

Introduction

This article demonstrates how to use WMI in ASP.NET to create a website, add a virtual folder, and add host headers. I have tested it using Windows Server 2003 and IIS 6.

It took me three days to get it working, some hours to write the code, and the remaining time finding out why I got a Win32: Access denied error. I could, of course, figure out that neither the NETWORK SERVICE or the IUSR_<servername> account has too many rights. I didn't have a clue, however, how WMI and the IIS metabase security work. I still don't, much, really. I did, however, solve my problem.

Using the code

To get a website ID from Internet Information Services Manager, click the 'Web Sites' node and check the column 'Identifier' for the ID. The default website always has the ID 1.

The functions we'll use are in this namespace, so include it:

using System.Management;

Hence the variable 'ServerName'. This is where you put your server's name, or a dot if it's the one you're running your code on.

To create a website, you'll want to use the following function. It returns the ID of the website that you can use in the functions mentioned further on.

public static string CreateWebsite(string serverName, string appPoolName, string ip, 
       string pathToRoot, string hostName, string domainName, int port)
{
    ConnectionOptions options = new ConnectionOptions();
    options.Authentication = AuthenticationLevel.Connect;
    options.EnablePrivileges = true;
    options.Impersonation = ImpersonationLevel.Impersonate;
    ManagementScope scope = new ManagementScope(string.Format(@\\{0}\root\MicrosoftIISv2, 
                            serverName), options);
    scope.Connect();
    ManagementObject oW3SVC = new ManagementObject(scope, 
    new ManagementPath(@"IIsWebService='W3SVC'"), null);

    ManagementBaseObject[] serverBindings = new ManagementBaseObject[1];
    serverBindings[0] = CreateServerBinding(scope, 
                        string.Format("{0}.{1}", hostName, domainName), ip, port);
    ManagementBaseObject inputParameters = oW3SVC.GetMethodParameters("CreateNewSite");
    inputParameters["ServerComment"] = string.Format("{0}.{1}", hostName, domainName);
    inputParameters["ServerBindings"] = serverBindings;
    inputParameters["PathOfRootVirtualDir"] = pathToRoot;
    ManagementBaseObject outParameter = 
      oW3SVC.InvokeMethod("CreateNewSite", inputParameters, null);

    string siteId = Convert.ToString(
     outParameter.Properties["ReturnValue"].Value).Replace(
     "IIsWebServer='W3SVC/", "").Replace("'", "");
    ManagementObject oWebVirtDir = new ManagementObject(scope, 
    new ManagementPath(string.Format(
        @"IIsWebVirtualDirSetting.Name='W3SVC/{0}/root'", siteId)), null);
    oWebVirtDir.Properties["AppFriendlyName"].Value = 
             string.Format("{0}.{1}", hostName, domainName);
    oWebVirtDir.Properties["AccessRead"].Value = true;
    oWebVirtDir.Properties["AuthFlags"].Value = 5; // Integrated Windows Auth.
    oWebVirtDir.Properties["AccessScript"].Value = true;
    oWebVirtDir.Properties["AuthAnonymous"].Value = true;
    oWebVirtDir.Properties["AppPoolId"].Value = appPoolName;
    oWebVirtDir.Put();

    ManagementObject site = new ManagementObject(scope, 
      new ManagementPath(Convert.ToString(
      outParameter.Properties["ReturnValue"].Value)), null);
    site.InvokeMethod("Start", null);
    return siteId;
}

To add a virtual folder:

public static void AddVirtualFolder(string serverName, string websiteId, 
                                    string name, string path)
{
    ManagementScope scope = new ManagementScope(
      string.Format(@"\\{0}\root\MicrosoftIISV2", serverName));
    scope.Connect();

    string siteName = string.Format("W3SVC/{0}/Root/{1}", websiteId, name);

    ManagementClass mc = new ManagementClass(scope, 
                    new ManagementPath("IIsWebVirtualDirSetting"), null);
    ManagementObject oWebVirtDir = mc.CreateInstance();

    oWebVirtDir.Properties["Name"].Value = siteName;
    oWebVirtDir.Properties["Path"].Value = path;
    oWebVirtDir.Properties["AuthFlags"].Value = 5; // Integrated Windows Auth.
    oWebVirtDir.Properties["EnableDefaultDoc"].Value = true;
    // date, time, size, extension, longdate ;
    oWebVirtDir.Properties["DirBrowseFlags"].Value = 0x4000003E;
    oWebVirtDir.Properties["AccessFlags"].Value = 513; // read script 
    oWebVirtDir.Put();

    ManagementObject mo = new ManagementObject(scope, 
      new System.Management.ManagementPath("IIsWebVirtualDir='" + 
      siteName + "'"), null);
    ManagementBaseObject inputParameters = mo.GetMethodParameters("AppCreate2");
    inputParameters["AppMode"] = 2;
    mo.InvokeMethod("AppCreate2", inputParameters, null);
    mo = new ManagementObject(scope, new System.Management.ManagementPath(
             "IIsWebVirtualDirSetting='" + siteName + "'"), null);
    mo.Properties["AppFriendlyName"].Value = name;
    mo.Put();
}

To add a host header to the website:

public static void AddHostHeader(string serverName, string hostHeader, 
       string ip, int port, string websiteID)
{ 
    ManagementScope scope = new ManagementScope(string.Format(
           @"\\{0}\root\MicrosoftIISV2", serverName));
    scope.Connect();

    string siteName = string.Format("'W3SVC/{0}'", websiteID);

    ManagementObject mo = new ManagementObject(scope, 
      new System.Management.ManagementPath("IIsWebServerSetting=" + siteName), null);
    ManagementBaseObject[] websiteBindings = 
      (ManagementBaseObject[])mo.Properties["ServerBindings"].Value;

    ManagementObject mco = CreateServerBinding(scope, hostHeader, ip, port);

    ManagementBaseObject[] newWebsiteBindings = 
      new ManagementBaseObject[websiteBindings.Length+1];
    websiteBindings.CopyTo(newWebsiteBindings, 0);
    newWebsiteBindings[newWebsiteBindings.Length - 1] = mco;

    mo.Properties["ServerBindings"].Value = newWebsiteBindings;

    mo.Put();
}

Last but not least, add the following function. It creates an object for server binding:

private static ManagementObject CreateServerBinding(ManagementScope scope, 
                                string hostName, string ip, int port)
{
    ManagementClass mc = new ManagementClass(scope, 
           new ManagementPath("ServerBinding"), null);
    ManagementObject mco = mc.CreateInstance();

    mco.Properties["Hostname"].Value = hostName;
    mco.Properties["IP"].Value = ip;
    mco.Properties["Port"].Value = port;
    mco.Put();

    return mco;
}

Points of interest

Security. This won't run just like this. Of the millions of things I've tried, there seem to be two things that need to be done. WMI and IIS metabase access.

Windows Server 2003 and IIS 6.0 run ASP.NET under NETWORK SERVICE, by default. But, we're going to use impersonation.

So you want to add this to your web.config:

<identity impersonate="true" />

The account used to grant your permission accessing the IIS metaBase will be the IUSR_<servername> account. I will continue to refer to this account just as IUSR_. You know you have to append your server's name.

WMI permission

  • Go to Control Panel -> Administrative Tools -> Computer Management -> Services & Applications.
  • Right-click WMI Control, choose Properties.
  • Click Security.
  • Open the tree.
  • Click MicrosoftIISv2.
  • Click Security.
  • Click Advanced.
  • Double click IUSR_ (or add it if it isn't there).
  • Select 'Apply onto': This namespace and sub-namespaces.
  • Check all the checkboxes.
  • Apply and Close all dialogs.

IIS metabase permission

  • Download and install the IIS 6 Resource Kit.
  • Run the MetaBase Explorer (find it in the Resource Kit menu under Start).
  • Open the tree, and right click the first or second node and choose Permissions.
  • If it complains about the current key inheriting from /, click Yes.
  • Click IUSR_ or add it.
  • Check Full Control.
  • Apply and Close all dialogs.

You should be ready to run with enough permissions.

It would be great if someone with more experience could comment on this and point out how to properly configure IIS and WMI to run this code. As I mentioned earlier, I found this out by trying, so I don't know if this is the optimal solution to the problem.

If someone has any problems running this code, I would like to help more.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

JeroenMX
Software Developer (Senior)
Mexico Mexico
No Biography provided

Comments and Discussions

 
GeneralVery Useful.. Some Questions Pinmembertimematcher8-Feb-10 1:09 
Hi there,
 
This is a very interesting article you posted. I have been trying to experiment modifying IIS 6.0 2k3 Server Settings via C# and this article came in handy.
 
Most of the things are quite self explanatory. And after a little googling , a lot of confusions became clear.
 
I was wondering,,if one can know basic and minimum algorithm to create a Website programmatically in C# (of course this code does it).
 
In other words, if you could point me to the theoretical material which may state the Algorithmic steps to performing various small steps/tasks in order to startup a website in IIS.
 

Some Important things I would Like to Add:
1. As far as the permissions stuff is concerned, one may set identity in web.config > system.web to an Administrator Local account..,,,or if it is being accessed remotely then an account who is added as Administrator at the Host machine may be used. e.g
 

 
Where DEV-9\admin is an Admin Account at Server and password_iis is its password.
 
2. oWebVirtDir.Properties["AuthFlags"].Value = 5; // Integrated Windows Auth.
has to be Set to 2 instead of 5 So that the password supplied in the web.config may work correctly...
 

Regards

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141220.1 | Last Updated 10 Feb 2009
Article Copyright 2009 by JeroenMX
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid