Introduction
If you have ever attempted to programmatically manipulate IIS in version 6 or earlier, you discovered that it is not a trivial endeavor! You could use Windows Management Instrumentation (WMI), ADSI, or write code to manually manipulate XML. It just wasn’t a task for the faint of heart! I have done it several times and remember it to be quite a headache.
Beginning with IIS 7, programmatic management of IIS has become much simpler with the Microsoft.Web.Administration objects. Using this API model, you can create websites, application pools, applications, virtual directories, etc. with just a few lines of code! Seriously!
The top-level objects of the API are illustrated below.
This post will walk you through some of the features of the Microsoft.Web.Administration namespace objects and provide some real-world examples of how to implement this really cool API.
Getting Started
If you have IIS installed on your development machine, you will be able to find the .dll in Windows\system32\inetsrv folder or you can use the Nuget package. Either way, you will need the Microsoft.Web.Administration.dll file as a reference in your project.
Once you add the necessary reference to your project, you are ready to go!
Working with the ServerManager
To get started, we must first create an instance of the ServerManager class. We do this exactly as you might think:
1
| ServerManager server = new ServerManager(); |
NOTE: It is important to note that an instance of the ServerManager assumes that the machine on which the application is running is the web server. It is possible to connect to a remote server using the ServerManager, and we will look at that later in this post.
Getting Sites Associated with the Server
Let’s get a list of all of the websites within our ServerManager. To do this, we access the Sites property of the ServerManager instance. The code block iterates each Site object.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| ServerManager server = new ServerManager(); SiteCollection sites = server.Sites; foreach (Site site in sites) { ApplicationDefaults defaults = site.ApplicationDefaults; //get the name of the ApplicationPool under which the Site runs string appPoolName = defaults.ApplicationPoolName; ConfigurationAttributeCollection attributes = defaults.Attributes; foreach (ConfigurationAttribute configAttribute in attributes) { //put code here to work with each ConfigurationAttribute } ConfigurationAttributeCollection attributesCollection = site.Attributes; foreach (ConfigurationAttribute attribute in attributesCollection) { //put code here to work with each ConfigurationAttribute } //Get the Binding objects for this Site BindingCollection bindings = site.Bindings; foreach (Microsoft.Web.Administration.Binding binding in bindings) { //put code here to work with each Binding } //retrieve the State of the Site ObjectState siteState = site.State; //Get the list of all Applications for this Site ApplicationCollection applications = site.Applications; foreach (Microsoft.Web.Administration.Application application in applications) { //put code here to work with each Application } } |
For more information regarding all of the properties and methods of the Site class, click here.
Getting Applications Associated with each Site
The applications that run under a Site are represented through the Applications property of the Site class. The Applications property is an ApplicationCollection object. We can iterate each Application object with the following code:
1
2
3
4
5
6
7
8
9
10
11
12
| ApplicationCollection applications = site.Applications; foreach (Microsoft.Web.Administration.Application application in applications) { //get the name of the ApplicationPool string applicationPoolName = application.ApplicationPoolName; VirtualDirectoryCollection directories = application.VirtualDirectories; foreach (VirtualDirectory directory in directories) { //put code here to work with each VirtualDirectory } } |
Getting Virtual Directories Associated with each Application
The virtual directories associated with each Application are accessible via the VirtualDirectories property of theApplication class. We can iterate each VirtualDirectory with the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| VirtualDirectoryCollection directories = application.VirtualDirectories; foreach (VirtualDirectory directory in directories) { ConfigurationAttributeCollection attribues = directory.Attributes; foreach (ConfigurationAttribute attribute in attributes) { //put code here to work with each attribute } ConfigurationChildElementCollection childElements = directory.ChildElements; foreach (ConfigurationElement element in childElements) { //put code here to work with each ConfigurationElement } //get the directory.Path string path = directory.Path; //get the physical path string physicalPath = directory.PhysicalPath; } |
Getting Application Pools Associated with a Server
The ServerManager.ApplicationPools property is an ApplicationPoolCollection object that contains all ApplicationPool objects associated with the server. Remember that this is a server-level property and that an ApplicationPool can be shared by multiple Sites and Applications.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| ServerManager server = new ServerManager(); ApplicationPoolCollection applicationPools = server.ApplicationPools; foreach (ApplicationPool pool in applicationPools) { //get the AutoStart boolean value bool autoStart = pool.AutoStart; //get the name of the ManagedRuntimeVersion string runtime = pool.ManagedRuntimeVersion; //get the name of the ApplicationPool string appPoolName = pool.Name; //get the identity type ProcessModelIdentityType identityType = pool.ProcessModel.IdentityType; //get the username for the identity under which the pool runs string userName = pool.ProcessModel.UserName; //get the password for the identity under which the pool runs string password = pool.ProcessModel.Password; } |
Now that we have taken a quick look at the object hierarchy and iterated through some of the child collections, let’s switch our view to how to create and manipulate objects.
Creating a New Application Pool
To create a new ApplicationPool, we create a ServerManager instance, then check the ApplicationPools collection to see if our ApplicationPool already exists. If it does, we update a few of its properties, if not we create the new ApplicationPool. Regardless of the whether we are creating or updating, we use theServerManager.CommitChanges() method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
| ServerManager server = new ServerManager(); ApplicationPool myApplicationPool = null ; //we will create a new ApplicationPool named 'MyApplicationPool' //we will first check to make sure that this pool does not already exist //since the ApplicationPools property is a collection, we can use the Linq FirstOrDefault method //to check for its existence by name if (server.ApplicationPools != null && server.ApplicationPools.Count > 0) { if (server.ApplicationPools.FirstOrDefault(p => p.Name == "MyApplicationPool" ) == null ) { //if we find the pool already there, we will get a referecne to it for update myApplicationPool = server.ApplicationPools.FirstOrDefault(p => p.Name == "MyApplicationPool" ); } else { //if the pool is not already there we will create it myApplicationPool = server.ApplicationPools.Add( "MyApplicationPool" ); } } else { //if the pool is not already there we will create it myApplicationPool = server.ApplicationPools.Add( "MyApplicationPool" ); } if (myApplicationPool != null ) { //for this sample, we will set the pool to run under the NetworkService identity myApplicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.NetworkService; //we set the runtime version myApplicationPool.ManagedRuntimeVersion = "v4.0" ; //we save our new ApplicationPool! server.CommitChanges(); } |
In the previous example, we set the ProcessModel.IdentityType to NetworkService. It’s a more common scenario to have a pre-defined service account that is most likely a domain account reserved specifically for this purpose. In this case, we can make a small modification to our code to implement this change. See below.
1
2
3
4
5
6
7
8
9
10
11
12
13
| if (myApplicationPool != null ) { //for this sample, we will set the pool to run under the identity of a specific user myApplicationPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser; myApplicationPool.ProcessModel.UserName = UserName; myApplicationPool.ProcessModel.Password = Password; //we set the runtime version myApplicationPool.ManagedRuntimeVersion = "v4.0" ; //we save our new ApplicationPool! server.CommitChanges(); } |
The UserName and Password values are strings that we would provide to our code when creating the ApplicationPool.
Creating a New Site
Creating a new Site is just as easy as creating a new ApplicationPool!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| ServerManager server = new ServerManager(); if (server.Sites != null && server.Sites.Count > 0) { //we will first check to make sure that the site isn't already there if (server.Sites.FirstOrDefault(s => s.Name == "MySite" ) == null ) { //we will just pick an arbitrary location for the site string path = @"c:\MySiteFolder\" ; //we must specify the Binding information string ip = "*" ; string port = "80" ; string hostName = "*" ; string bindingInfo = string .Format( @"{0}:{1}:{2}" , ip, port, hostName); //add the new Site to the Sites collection Site site = server.Sites.Add( "MySite" , "http" , bindingInfo, path); //set the ApplicationPool for the new Site site.ApplicationDefaults.ApplicationPoolName = myApplicationPool.Name; //save the new Site! server.CommitChanges(); } } |
We have only touched on some of the functionality provided to us by the Microsoft.Web.Administration namespace objects. For more information, this MSDN resource is a great place to start. Remember that this API is only valid for IIS version 7.0 and higher and that if you seek to automate a prior version your plan of attack will be quite different.
More