November, 2007

November, 2007

  • Care, Share and Grow!

    My IIS 7.0 Administration UI Extension Page


    The UI extension option in IIS 7.0 is an exciting feature for any .Net developer. You can write your own custom UI pages and can add various features to it to manage IIS on Windows Vista and Windows Server 2008. I have written an UI extension and is attached with this post.

    I have added the IIsReset feature provided by my good friend Rakki as part of this UI module. He had blogged about it here. Besides IISRESET, I have also added an integrated browser, AppCmd.exe UI and a generic Request monitoring tab.

    To add this module in your IIS 7 manager follow the steps below:

    1. Download the ExtensibilityDemo.dll.
    2. Drag and Drop the ExtensibilityDemo.dll into the Global Assembly Cache (C:\Windows\assembly) or use GacUtil -i ExtensibilityDemo.dll to install it to the GAC.
    3. From the Windows Explorer, browse to the file



        4. Search for the <moduleProviders> section and add the following

    <add name="ExtensibilityDemo" type="ExtensibilityDemo.DemoModuleProvider, ExtensibilityDemo, Version=, Culture=neutral, PublicKeyToken=204f1a1ad20ba534" />

    You need to crosscheck that PublickKeyToken matches what is present in the GAC.

    This should be same as the following in the Assembly folder:


        5. Search for the <modules> section and add the following

    <!-- For all Sites -->
      <location path=".">
          <add name="ExtensibilityDemo" />


        6. Open Inetmgr (Start Menu->Run->Inetmgr) and You will see the module listed in your IIS 7 Manager if everything went fine during the installation.

    You can see the Module listed in Connections Pane as well as middle pane in its own category. If you want you can remove from the Connections Pane by right click and "remove".

    Here are some screen shots for this extension:


    In the central IIS manager pane (window) you should see the following:





    image image

    I will be adding some new functionalities as time progresses to have more UI interface for various features. I will recommend if you are interested start developing your modules today to customize/extend IIS 7.0 features.

    Good luck....

  • Care, Share and Grow!

    Accessing iis 7.0 features programmatically from configuration file(S) (C#)


    IIS 7.0 has great features for developers now. It is integrated with .Net. UI has completely changed from the previous versions. It has entirely a new look and feel. I feel there would be a steep learning curve for IIS users, but nothing to worry, unlike previous versions this time we have done our homework well. has lot of important material on IIS 7.0 should a user want to know. Our IIS developers/managers have blogged extensively on various aspects of the new features coming up with IIS 7.0. Time has really changed now when it comes to IIS :-)

    To continue with where I left earlier, I will show how extensively you can play with IIS features programmatically, which was really difficult with earlier versions. Now you have .Net, WMI scripts with which you can code in C++, C#, VB Script for example.

    I will use C# here and take advantage of the new API for accessing IIS configurations.

    In my demo, I will dig into the ApplicationHost.config file through code to find out information of our interest. Here I will get information about application pool settings etc and later on default document settings for a specific web application.

    My aim is not to have a very reliable and error free code. I haven't handled any exceptions etc. that may arise. The objective here is how you can dig deep to any level in the config file to get information on various features related to IIS, your web site or application.

        using (ServerManager localServer = new ServerManager())
                        Configuration config = localServer.GetApplicationHostConfiguration();
                        // Get or Set Application Pool settings on the IIS 7.0 server
                        // Here we look for ApplicationPools section in the config file. 
                        // IIS_Schema.xml is the file that contains the schema for all the settings we find in ApplicationHost.config file.
                        ConfigurationSection appPoolConfigSection = config.GetSection("system.applicationHost/applicationPools");
                       ConfigurationElementCollection appPoolCollection = appPoolConfigSection.GetCollection();
                       //Since there is a collection "add" within system.applicationHost/applicationPools section, 
                       // we will reiterate through few of its attributes and child elements only.
                       Console.WriteLine("Application Pool settings");
                       foreach (ConfigurationElement element in appPoolCollection) // Iterates through all the Application Pools.
                           Console.WriteLine("Name: " + element.GetAttributeValue("name").ToString());
                           Console.WriteLine("Pipleline Mode: " + element.GetAttributeValue("managedPipelineMode").ToString());
                           //'processModel' is a child element within the collection 'add'
                           ConfigurationElement processModel = element.GetChildElement("processModel");
                           Console.WriteLine("Process Model: " + processModel.GetAttributeValue("identityType"));
                           Console.WriteLine("App pool Identity: " + processModel.GetAttributeValue("userName"));
                           ConfigurationElement recycling = element.GetChildElement("recycling");
                           ConfigurationElement periodicRecyclingSettings = recycling.GetChildElement("periodicRestart");
                           Console.WriteLine("Periodic Recycling Parameters: ");
                           Console.WriteLine("Memory: " + periodicRecyclingSettings.GetAttributeValue("memory"));
                           Console.WriteLine("Private Memory: " + periodicRecyclingSettings.GetAttributeValue("privateMemory"));
                           Console.WriteLine("Requests: " + periodicRecyclingSettings.GetAttributeValue("requests"));
                           Console.WriteLine("Time: " + periodicRecyclingSettings.GetAttributeValue("time"));

    If you notice here we can query all the IIS related configurations from the ApplicationHost.config file. If you have some Web site related settings you can query that from the web.config file declared for the web site or else from the Applicationhost.config file (it is set using Location tag, like <Location Path="Default Web site/Virtdir">).
    In the above code we queried the Applicationhost.config file to get the settings. If you notice you can dig deep into the hierarchy and get the information related to a specific collection, element, attribute etc. All these tags basically contain some IIS related settings.
    The information related to various tags like whether a specific tag is a collection or child element or an attribute etc, are defined in the IIS_Schema.xml file. If you want to use your own custom properties you can create your own schema file and save it to the schema folder. Never modify the IIS_Schema.xml file. Here is a snippet of how IIS_schema.xml file looks like.

    <sectionSchema name="system.applicationHost/applicationPools">
        <collection addElement="add" defaultElement="applicationPoolDefaults">
          <attribute name="name" type="string" required="true" isUniqueKey="true" validationType="applicationPoolName" />
          <attribute name="queueLength" type="uint" defaultValue="1000" validationType="integerRange" validationParameter="10,65535"/>
          <attribute name="autoStart" type="bool" defaultValue="true" />
          <attribute name="enable32BitAppOnWin64" type="bool" defaultValue="false" />
          <attribute name="managedRuntimeVersion" type="string" defaultValue="v2.0" />
          <attribute name="managedPipelineMode" type="enum" defaultValue="Integrated">
            <enum name="Integrated" value="0" />
            <enum name="Classic" value="1" />
          <element name="processModel">
            <attribute name="identityType" type="enum" defaultValue="NetworkService">
              <enum name="LocalSystem" value="0"/>
              <enum name="LocalService" value="1"/>
              <enum name="NetworkService" value="2"/>
              <enum name="SpecificUser" value="3"/>
            <attribute name="userName" type="string"/>
            <attribute name="password" type="string" encrypted="true" defaultValue="[enc:IISWASOnlyRsaProvider::enc]" />
          <element name="recycling">
            <attribute name="disallowOverlappingRotation" type="bool" defaultValue="false"/>
            <attribute name="disallowRotationOnConfigChange" type="bool" defaultValue="false"/>
            <element name="periodicRestart">
              <attribute name="memory" type="uint" defaultValue="0" />
              <attribute name="privateMemory" type="uint" defaultValue="0" />
              <attribute name="requests" type="uint" defaultValue="0" />
              <attribute name="time" type="timeSpan" defaultValue="29:00:00" validationType="timeSpanRange" validationParameter="0,25920000,60"/>


    Now let's list/add/remove one of the values in the existing configuration of our server programmatically. Let's add a file "mypage.html" to the default Document list of my application 'App1' under the Default Web site.
                 One thing you may notice is that if you modify the default document setting through IIS mmc UI, there will be a web.config file created in your application folder with the reflected changes.

    using (ServerManager localServer = new ServerManager())
        Configuration config = localServer.GetApplicationHostConfiguration();
        // IIS_Scema.xml is the file that contains the schema for all the settings we find in 
        // ApplicationHost.config file.
     ConfigurationSection defaultDocumentSection = config.GetSection("system.webServer/defaultDocument", "Default Web Site/App1");
     // Now since defaultDocument is a section in itself querying or modifying the settings should be only a few lines. 
     // Remember we are not digging inside the hierarchy to get any collection, child, element etc. Its defined as a section itself.
     // here we intend to set the default document for the application App1 under Default Web site.
     Console.WriteLine("Default Document is enabled: " + defaultDocumentSection.GetAttributeValue("enabled"));
     ConfigurationElement files = defaultDocumentSection.GetChildElement("files");
     //Since in IIS_Schema, you will notice files is an element within Section "system.webServer/defaultDocument"
     ConfigurationElementCollection filesCollection = files.GetCollection();
     //Since Add, Clear and Remove form a part of the Collection within "files" withinn Section "system.webServer/defaultDocument".
     foreach (ConfigurationElement defaultPage in filesCollection)
     // Now let's programmatically add a file to the list of default Documents. We can also enable/disable the feature at any site/app level.
    ConfigurationElement newfile = filesCollection.CreateElement();
     newfile.SetAttributeValue("value", "mypage1.html");
     localServer.CommitChanges(); // in order to reflect the changes in the physical ApplicationHost.config file.

    Let's remove the file from the list that we added through code.

    //Removing a file from the default Document list
             using (ServerManager localServer = new ServerManager())
                 Configuration config = localServer.GetApplicationHostConfiguration();
                 ConfigurationSection defaultDocumentSection = config.GetSection("system.webServer/defaultDocument", "Default Web Site/App1");
                 ConfigurationElement files = defaultDocumentSection.GetChildElement("files");
                 ConfigurationElementCollection filesCollection = files.GetCollection();
                 foreach (ConfigurationElement file in filesCollection)
                     if (String.Equals(file.GetAttributeValue("value").ToString(), "mypage1.html", StringComparison.OrdinalIgnoreCase))
                         break; // Since you cannot have duplicate files as Default document. 

    You should see the following tree hierarchy for this setting in the config file, either at the Application root (as web.config) or in the ApplicationHost.config file with a location tag.

                     <clear />
                     <add value="Default.htm" />
                     <add value="Default.asp" />
                     <add value="index.htm" />
                     <add value="index.html" />
                     <add value="iisstart.htm" />
                     <add value="default.aspx" />
                     <add value="mypage1.html" />

    There are a lot of thing that you can do through code in order to manage IIS 7.0.

    One can write their own custom module, handler and plug into the IIS pipeline. This module need not be written any more in C++ to act as a native ISAPI. One can write a managed module/handler and plug it to IIS configuration and it will serve both managed and non-managed resources.

    This is a big news for .Net based developers!!!

  • Care, Share and Grow!

    my first post on IIS 7.0......lot to explore yet :)


    Recently I have started exploring IIS 7.0 and one word that can express my feeling is "WOW!". IIS 7.0 is way ahead of all the previous versions of IIS. I have worked extensively with IIS 5.0/5.1/6.0 and I can say for sure, IIS 7.0 is completely in a different league of its own. There are many new features embedded in it which were not present in the earlier versions. Important ones are like Integrated Pipeline, Automatic Application Pool Isolation, Extensibility, Modularization etc. I would love to go on talking about what IIS 7.0 is and what all customizations you can go on doing with it. It has opened a wide array of opportunities for Web Admins and developers alike. I am pretty sure the Web Hosters would love it. You have the option to delegate Admin privileges to the users for specific sites/applications hosted on the Web server.

    To cut the long story short I will not go into the details of the various features and come to the topic of this blog. In case you are interested to know more about IIS 7.0 just visit and there are some really cool articles/blogs/downloads waiting for your eyes to be laid upon them :-)

    I started playing with IIS 7.0 and found that it is really interesting for developers, native and managed based alike.

    Here I will show ways in which you can determine various information about Web Sites, Virtual Directories, Applications etc. through simple code written in C#. You can use the functionality to get on to advanced usage. My main motive is to show that things have become really simple with IIS 7.0.

    ApplicationHost.config file has become what metabase.xml in IIS 6.0 and metabase.bin in IIS 5.0/5.1 were meant for. Although they are not exactly the same but they serve the same purpose.

    Here I have the code (Ignore the formatting/minor errors if any ;-)) which reads the ApplicationHost.config file based on the schema from IIS_Schema.xml (By default, it will be under the folder %Systemdrive%\Windows\System32\inetsrv\config\schema.

    What is worth noting is that reading configuration data is similar to reading web.config in ASP.Net. In fact IIS 7.0 is very tightly  coupled with ASP.Net now.

    Microsoft.Web.Administration namespace contains many useful features to programmatically get data for IIS 7.0 configuration. Explore it and you will find lot many interesting options available.

    Here I have added some relevant section for my code from the above config file. Notice how you can programmatically fetch data from the ApplicationHost.config file.

    ApplicationHost.config snippet:



                   <sectionGroup name="system.applicationHost">
                             <section name="sites" allowDefinition="AppHostOnly" overrideModeDefault="Deny" />





                  <site name="test" id="2" serverAutoStart="false">
                           <application path="/">
                                  <virtualDirectory path="/" physicalPath="E:\Visual Studio Express\testwebsite" />
                                  <virtualDirectory path="/aspnettest" physicalPath="E:\Visual Studio Express\aapnetlearn" />


    <Code Snippet>

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Web.Administration;
    namespace IIS7codeDemo
        class Program
           static void Main(string[] args)
               ServerManager sm = new ServerManager();
               Configuration config = sm.GetApplicationHostConfiguration();  // <--- Reading the ApplicationHost.config file
               ConfigurationSection cfgSection = config.GetSection("system.applicationHost/sites"); // <-- Picking up Web sites section in the ApplicationHost.config file.
               ConfigurationElementCollection configEleColl0 = cfgSection.GetCollection(); // <-- Since various sites are collection elements under the /Sites section, we read the whole Site collection.
               //Iterating through each collection
               foreach (ConfigurationElement cfgElement0 in configEleColl0) // <--- <sites>....</sites>
                   Console.WriteLine("Site Name:  " + cfgElement0.GetAttributeValue("name"));
                   ConfigurationElementCollection configEleCol1 = cfgElement0.GetCollection(); // <--- <application>....</application>
                   foreach (ConfigurationElement cfgElement1 in configEleCol1)
       //              Console.WriteLine("Application Virtual Path in " + cfgElement0.GetAttributeValue("name")+":" + cfgElement1.GetAttributeValue("path"));
                       ConfigurationElementCollection configEleCol2 = cfgElement1.GetCollection(); // <--- <virtualDirectory>....</virtualDirectory>
                       foreach (ConfigurationElement cfgElement2 in configEleCol2)
                           Console.Write("Virtual Path: " + cfgElement1.GetAttributeValue("path")+ cfgElement2.GetAttributeValue("path")); // <--- Reading Virtual Path attribute
                           Console.WriteLine("    " + "Physical Path: " + cfgElement2.GetAttributeValue("physicalPath"));  // <--- Reading Physical Path attribute

    Here we have queried for the Web site, Virtual Directory etc.


    Site Name:  Default Web Site
    Virtual Path: //    Physical Path: %SystemDrive%\inetpub\wwwroot
    Virtual Path: /widget/    Physical Path: C:\inetpub\wwwroot\widget
    Virtual Path: /widget/vd3    Physical Path: E:\CPP
    Virtual Path: /blogsite/    Physical Path: E:\Visual Studio Express\New Folder
    Virtual Path: /App1/    Physical Path: D:\test
    Virtual Path: /widget/vd3/app6/    Physical Path: c:\Inetpub

    You can query for any other information like Application pools, bindings, modules, handler etc. In fact you can get most of the information that is present in ApplicationHost.config file programmatically.

    Another way you can  get the above information is via classes available in the Microsoft.Web.Administration namespace.

    Here is another code snippet which gets the above information not by reading the ApplicationHost.config file but by using managed .Net classes available for such queries.

    Code Snippet:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Web.Administration;
    namespace IIS7Demo
        class Program
           static void Main(string[] args)
               ServerManager mgr = new ServerManager();
               SiteCollection allSites = mgr.Sites;
               foreach (Site site in allSites)
                   ApplicationCollection allApplications = site.Applications;
                   foreach (Application app in allApplications)
                       VirtualDirectoryCollection vdc = app.VirtualDirectories;
                       foreach (VirtualDirectory virDir in vdc)
                           string temp = app.Path + virDir.GetAttributeValue("path") + "     Loc: " + virDir.GetAttributeValue("physicalPath");
                           string output = temp.Replace("//", "/");

    Till next time...

  • Care, Share and Grow!

    Wildcard SSL certificate in IIS 6.0, Windows 2003 Sp1 and above


    Here I will be talking about configuring SSL wildcard certificates in IIS 6.0 on Win2k3 SP1 and above.

    You may have a scenario wherein you want to have the same certificate installed for multiple Websites. Now in a normal scenarios this is not possible.

    What I mean is you cannot have the same certificate installed on multiple Websites. To achieve a similar functionality you need to get a wildcard certificate from a Certificate Authority.

    A wildcard certificate can be applied when you have the same end-domain name for all your Websites wherein you want to install the certificate.

    Let's say you have Websites like, and Here the same end-domain name is present which is

    Also remember that you can install the certificate for all such Websites when all of them are running under the same IP/Port combination. Here host headers will be the identifying criteria for Websites.

    So let's say you have the following configuration:

    WebSite                   Host Header Value                  IP Address                Port             SSL Port
    Test1                                                 80                  443
    Test2                                                   80                  443

    Test3                                               80                  443

    and you want to use the same certificate for all the above Websites, Wildcard certificate is a viable option.

    Here are the steps to obtain a wildcard certificate through IIS manager:

    -In IIS Manager, expand the local computer, and then expand the Web Sites folder.

    -Right-click the Web site for which you want to obtain a wildcard server certificate, and then click on Properties.

    -On the Directory Security tab, under Secure communications Button, click Server Certificate.

    -In the Web Server Certificate Wizard, click Create a new certificate.

    -Follow the Web Server Certificate Wizard, which will guide you through the process of requesting a new server certificate. You can have any name in the Wizard which shows Name and Security Settings. On the 'Your Site's Common Name' page, type a name in the Common name box, using the following format:
    *.<sitename> for example, * (as in our scenario).

    By default, the certificate request file is saved as C:\Certreq.txt, but the wizard allows you to specify a different location of your choice.

    -Click Finish to complete the wizard.

    After you receive the wildcard server certificate from the Certification Authority, assign the same certificate on all Web sites that have the same IP/port binding and are distinguished only by the host header name.

    Here is a Screenshot of the wildcard certificate that we got for our * sites.


    Now at this point if you try to access any of the Websites you will see that all of the HTTPS responses come from one specific site.

    What I mean is that if you access, or https://hrweb/ you will get the response from one site only.

    You won't get the corresponding web pages from different Websites depending upon the site in URL. You will  also see that only one of the Websites will be running. Other Websites will be in stopped state because we cannot have multiple Websites running with same IP and same SSL port binding (without of course some extra settings). If you try to start the other Websites you may see something like this below:


    Now, the next most important thing is to follow the script below:

    Go to Start Menu, click Run, type "cmd", and then click OK.

    Type the following command at the command prompt:

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/<site identifier>/SecureBindings ":443:<host header>"                       <--- [It's not case sensitive]

    where host header is the host header for the Web site, for example, or


    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/1/SecureBindings ""

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/2/SecureBindings ""

    C:\Inetpub\AdminScripts>cscript.exe adsutil.vbs set /w3svc/3/SecureBindings ""

    Now once we have these settings in place for the Websites you should be able to browse to the Websites. You will also be able to start all the Websites without any issues.

    Ensure that you do not modify any of the SSL related settings in the IIS manager like host header etc. after doing the changes in the metabase.

    Finally have SSLDiag handy in case you get into issues for any general SSL related troubleshooting :-)

  • Care, Share and Grow!

    You get a Security Alert when you try to access an SSL enabled web site when certificate has been issued by an internal root CA...


    Let's say you have your own internal Root Certificate Authority (CA) and you use it to grant server certificates to your Web sites.

    You are able to browse to your web site over SSL and can access the page. Things look good so far.

    However you get an unwanted security alert all the time while accessing the page, stating the following:


    "The security certificate was issued by a company you have not chosen to trust.

    View the certificate to determine whether you want to trust the certifying authority"


    "This certificate cannot be verified up to a trusted certification authority" in the Certificate ->General tab.


    And if you have mobile access users they won't be able to access the page at all :-(, forget the Security alert.

    Also if your Web site is Internet-facing, that means both internal as well as external users should be able to access the web site, then you will see a little different behavior.

    What does it mean? Well, as the message description above clearly states we do not have information about the Root CA to verify whether it can be trusted for SSL transactions. Since you are using an internal Root CA for your Web site certificates, IE on the external client has no way to verify whether the root CA is trusted or not. IE has a list of default trusted root CA's.

    If you check IE->Tools->Internet Options->Content->Certificates->Trusted Root Certification Authorities, you will see a list of all the public Root CA's that are trusted by IE client like VeriSign, Go Daddy, Thawte etc.




    From an external IE (here assuming IE7) client, If you go to the Certificate Error->View certificates->"Certification Path" as in the above screenshot you should only see the Web site certificate listed.

    If you check the above from an intranet client you will see an hierarchy showing both the Root CA and the Web site certificates.



    Why the above difference?

    Since Intranet client has access to the Internal Root CA they (IE) see the hierarchy of Root CA and the Web site certificate in the Certificate->"Certification Path",


    You will be able to see both the root CA and the Web site certificate as above.

    But since root CA is not accessible for the Internet users they will only see the Web site certificate and not the Root CA certificate in the tree in the "Certification Path". Root CA will be absent altogether in the tree. Or else you will see an entry for the root CA but with a RED X meaning that CA Root certificate is not trusted as it is not in the Trusted Root Certification Authorities store on the client.


    You get "This certificate cannot be verified up to a trusted certification authority" when the Certificate Authority is not running or is not visible to the client (IE). This generally happens when client cannot access CA for e.g. running your internal CA and users accessing the web site over Internet.

    We will have to install the root CA certificate on to the client computer in order to get rid of the security alert.

    For intranet users downloading and installing the .cer of the Root CA into the Trusted Root Certification Authority MAY resolve the issue.

    Else, here are the steps to successfully install the root certificate authority on to the client's trusted CA store:

    • On the IIS or Certificate Server, open MMC (Start->Run and type MMC) and add the Certificates snap-in using the Computer Account.
      -- Expand Certificates

    -- Expand Trusted Root Certification Authority.
    -- Right click on the correct Root Certification Authority -> Click Export, which opens the wizard. Choose the following in the wizard:
              a) Check "Cryptographic Message Syntax Standard - PKCS #7 Certificates (.P7B)"
              b) Check "Include all certificates in the certification path if possible" --> click Next
              c) Give it a relevant file name (in our case, say RootCAFileName) and choose the location --> Click Next
              d) Click Finish

    This will create RootCAFileName.p7b.
    -- Copy RootCAFileName.p7b to the client.
    -- It can be installed on the client machine in two ways: 

    By Right click on the RootCAFileName.p7b file or by using IE via Import.


    - Right-click on RootCAFileName.p7b -> Click "Install Certificate" -> Next
    - Click "Place all certificates in the following store" -> Browse
    - Select "Trusted Root Certification Authorities" -> Ok -> Next

    - Click Finish

    - Open IE -> Tools menu -> Internet Options
    - Go to the Content tab -> Click Certificates
    - Go to the "Trusted Root Certification Authorities" tab -> Click Import
    - Follow steps in the wizard to browse to the RootCAFileName.p7b file and place it in "Trusted Root Certification Authorities" -> Next
    - Finish


    Hope this helps...

Page 1 of 1 (5 items)