Configuring IIS using Directory Services and C#

Introduction

Hi Folks,

It has been a while since I last posted, been very busy at work and I decided to take a holiday in Portugal, I spent most of my time surfing in Peniche, lovely place!

We just finished a major development phase at work and the next step was deployments, one aspect of the deployments is Application Pools and Web Service virtual directories, we have allot of web services and would it be nice to automate the creation of these items in the IIS system.

I decided the best way to go is to use WMI, C# and the System.DirectoryServices library.

This article will discuss how to browse the WMI repository and write code in C# to create and configure application pools as well as virtual directories, this article will cover some advanced features of accessing Directory Service object properties which in turn customize the properties of IIS objects such as the recycle schedule in the Application Pool settings and Identity account information.

WMI Studio

The first thing you need to do before we get going is download the WMI Studio tools, they are a great help in understanding WMI objects when developing, you can download it from here:

http://www.microsoft.com/downloads/details.aspx?FamilyID=6430f853-1120-48db-8cc5-f2abdc3ed314&displaylang=en

Install the tools and you will find the following link in your program menu:

When you click on the WMI CIM Studio shortcut, you will be presented with the following browser:

I advise you to click the warning message and click "Allow Blocked Content"

You will then be presented with the following screen:

Change the connection to:

root\MicrosoftIISv2

And then click ok twice. You will be presented with the following page:

We are now in the IIS repository and can start browsing around it. Let’s say we would like to understand how the CIM stores information regarding the Application Pools in IIS. Notice a section call CIM_Setting:

This is basically the place to look for a Class that defines the settings for the application pool, in fact the class name is called:

IIsApplicationPoolsSetting

If you browse to it, it is near the bottom, you will notice all the settings, for example, the PeriodicRestartSchedule is this setting in IIS admin console:

Ok, so now how about looking at some of the settings in the current IIS system, we can do this, remember what you browsing is a Class Definition and you can create an instance of one from this tool by clicking this button on the top right and then fill in the properties and save it, but we going to do it programmatically:

But before we get down to the dirty details and exciting bits, I want you to understand some basic WQL queries, what we going to do is look at the settings of the Default Application Pool in IIS, so we going to look at an INSTANCE of a object that is already configured in IIS, why? Because this can help you reverse engineer what properties mean in the GUI and correlate them back to the property names in the WMI repository, just like I shoed you with the property PeriodicRestartSchedule property of the application pool properties collection.

So click this icon:

It will open up a dialog box, and we will enter the following query in it:

select * from IIsapplicationPoolSetting

save the query by giving it a name as well!

Then click execute.

It will now show you what the IIS admin tool shows, the application pools:

Double click the DefaultAppPool, and you can then see the properties. Now if you change values in IIS admin console and then reconnect to this CMI database you can figure out what properties changed!

Ok, so I hope my short introduction here will suffice to get you going, let’s get to the exciting bit.

Configuration

Of course with any tool, you need configuration to be stored somewhere, suppose we have this XML configuration file:

<?xml version="1.0" encoding="utf-8" ?>

<Settings>

    <IIS_Settings>

        <ApplicationsPools>

            <ApplicationPool>

                <Server>local</Server>

                <Name>DataCleansingAppPool</Name>

                <UserName>DEVPlace\Gateway</UserName>

                <Password>sdf</Password>

                <Identity>Configurable</Identity>

                <RecycleWorkerProcessInMinutes>0</RecycleWorkerProcessInMinutes>

                <RecycleWorkerProcessSchedule>12:00</RecycleWorkerProcessSchedule>

            </ApplicationPool>

            <ApplicationPool>

                <Server>local</Server>

                <Name>Gateway Web Service</Name>

                <UserName>DEVPlace\Gateway</UserName>

                <Password>sdf</Password>

                <Identity>Configurable</Identity>

                <PeriodicRestartTime>0</PeriodicRestartTime>

                <PeriodicRestartSchedule>12:00</PeriodicRestartSchedule>

            </ApplicationPool>

        </ApplicationsPools>

        <WebSites>

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.DataCleansingWS</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.DataCleansing\MMIT.DataCleansingWS</LocalPath>

                <ApplicationPool>DataCleansingAppPool</ApplicationPool>

            </WebSite>

 

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.DataManipulation.WebServices</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.DataManipulation\MMIT.DataManipulation.WebServices</LocalPath>

                <ApplicationPool>DefaultAppPool</ApplicationPool>

            </WebSite>

 

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.DealerAllocation.WebServices</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.DealerAllocation\MMIT.DealerAllocation.WebServices</LocalPath>

                <ApplicationPool>DefaultAppPool</ApplicationPool>

            </WebSite>

 

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.DeliveryNotification.WebServices</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.DeliveryNotification\MMIT.DeliveryNotification.WebServices</LocalPath>

                <ApplicationPool>DefaultAppPool</ApplicationPool>

            </WebSite>

 

 

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.Gateway.WebServices</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.Gateway\MMIT.Gateway.WebServices</LocalPath>

                <ApplicationPool>Gateway Web Service</ApplicationPool>

            </WebSite>

 

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.Matching.WebServices</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.Matching\MMIT.Matching.WebServices</LocalPath>

                <ApplicationPool>DefaultAppPool</ApplicationPool>

            </WebSite>

 

            <WebSite>

                <Server>local</Server>

                <VirtualDirectoryName>MMIT.Workflow.Common.WebServices</VirtualDirectoryName>

                <LocalPath>C:\Code\MMIT.Workflow\MMIT.Workflow.Common.WebServices</LocalPath>

                <ApplicationPool>DefaultAppPool</ApplicationPool>

            </WebSite>

 

            

        </WebSites>

    </IIS_Settings>

 

</Settings>

 

Implementing the code

To configure the values above, I will show you how to do it for the application pool and you can figure out how to do it for the virtual directories. A good article that can help is here:

http://msdn.microsoft.com/en-us/library/ms524896.aspx

 

I have the following C# code in my windows form you can of course make it a console application

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.IO;

using System.Text;

using System.Windows.Forms;

using System.Xml;

 

namespace MMIT.Workflow.InstallationConfiguration

{

public partial class Form1 : Form

{

 

private readonly static XmlDocument doc = new XmlDocument();

private static FileStream fs;

private readonly static ASCIIEncoding encoding = new ASCIIEncoding();

 

private enum Identity {Predifined=2, Configurable=3} //PreDefined defaults to NetworkService in IIS settings

 

 

public Form1()

{

InitializeComponent();

doc.Load(@"..\..\MMIT.Workflow.InstallationConfiguration.xml");

}

 

private void btnIISSetup_Click(object sender, EventArgs e)

{

txtIISOutput.Text += CreateApplicationPools();

CreateVirtualDirectories();

}

 

 

 

private string CreateApplicationPools()

{

string output="";

foreach (XmlElement element in doc.SelectSingleNode("Settings/IIS_Settings/ApplicationsPools").ChildNodes)

{

string Server = element.SelectSingleNode("Server").InnerText;

string AppName = element.SelectSingleNode("Name").InnerText;

string UserName = element.SelectSingleNode("UserName").InnerText;

string Password = element.SelectSingleNode("Password").InnerText;

int IdentitySetting = element.SelectSingleNode("Identity").InnerText == "Configurable" ? (int)Identity.Configurable : (int)Identity.Predifined;

int PeriodicRestartTime = int.Parse(element.SelectSingleNode("RecycleWorkerProcessInMinutes").InnerText);

string PeriodicRestartSchedule = element.SelectSingleNode("RecycleWorkerProcessSchedule").InnerText;

output += IISAdministration.CreateaApplicationPool(AppName, UserName, Password, IdentitySetting, PeriodicRestartTime, PeriodicRestartSchedule) + Environment.NewLine;

}

return output;

}

 

 

private void CreateVirtualDirectories()

{

 

}

}

}

 

Here is the class that implements the logic:

using System;

using System.DirectoryServices;

 

 

namespace MMIT.Workflow.InstallationConfiguration

{

class IISAdministration

{

private const string WMINameSpace = @"root\MicrosoftIISv2";

private const string metabasePath = "IIS://Localhost/W3SVC/AppPools";

 

 

 

 

public static string CreateaApplicationPool(string appPoolName, string userName, string password, int identity, int periodicRestartTime, string PeriodicRestartSchedule)

{

string output = "\nCreating application pool named:" + metabasePath + "/" + appPoolName + Environment.NewLine;

 

try

{

if (metabasePath.EndsWith("/W3SVC/AppPools"))

{

DirectoryEntry newpool;

DirectoryEntry apppools = new DirectoryEntry(metabasePath);

newpool = apppools.Children.Add(appPoolName, "IIsApplicationPool");

newpool.Properties["WAMUserName"][0] = userName;

newpool.Properties["WAMUserPass"][0] = password;

newpool.Properties["AppPoolIdentityType"][0] = identity;

 

newpool.Properties["PeriodicRestartTime"][0] = periodicRestartTime;

newpool.Properties["PeriodicRestartSchedule"].AddRange(new string[] { PeriodicRestartSchedule });

 

 

 

newpool.CommitChanges();

output += "Done." + Environment.NewLine;

}

else

output = " Failed in CreateAppPool; application pools can only be created in the */W3SVC/AppPools node." + Environment.NewLine;

}

catch (Exception ex)

{

output = "Failed in CreateAppPool with the following exception:" + ex.Message + Environment.NewLine;

}

return output;

}

}

}

 

Certain properties are access like an array, however some properties are a bit more complex, like the schedule settings for recycling worker processes, so what you do here is check in the CIM what the data type is and then it correctly:

newpool.Properties["PeriodicRestartSchedule"].AddRange(new string[] { PeriodicRestartSchedule });

Other settings are easier:

newpool.Properties["WAMUserName"][0] = userName;

The CMI property page can give you clues:

 

Hence why I instantiated the PeriodicRestartSchedule, since it is an unitilized array, since it needs an array of configured objects to begin with, if you tried this:

newpool.Properties["PeriodicRestartSchedule"][0]

You would have gotten an index out of range exception.

Summary

Well, I hope this article has discusses some WMI programming for you, at a later time I may update this blog and provide a fully functional working admin tool kit that you can extend for IIS, BizTalk etc.

Advertisements
Uncategorized

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s