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

WMI Functions from ASP.NET

By , 10 Feb 2009
Rate this:
Please Sign up or sign in to vote.

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)

About the Author

JeroenMX
Software Developer (Senior)
Mexico Mexico
No Biography provided

Comments and Discussions

 
GeneralVery Useful.. Some Questions Pinmembertimematcher8-Feb-10 0:09 

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 | Mobile
Web02 | 2.8.140415.2 | Last Updated 10 Feb 2009
Article Copyright 2009 by JeroenMX
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid