Modifying IIS 7.0 Administration.config using Javascript and AHADMIN

AHADMIN is the COM API that IIS 7.0 uses for reading and writing its configuration system. One of the not so well known features is that you can also use the same API to manage Administration.config by calling the SetMetadata method and specifying that you will be targeting Administration.config. What this ends up doing is using an IAppHostPathMapper built-in mapper that will re-map the files so that you can manage Administration.config easily.

Here is an example of a common operation that adds a ModuleProvider (UI Extensibility Module) and its corresponding Module.

// Create a Configuration System for modifying Administration.config
var adminManager = new ActiveXObject("Microsoft.ApplicationHost.WritableAdminManager");
adminManager.CommitPath = "MACHINE/WEBROOT";
adminManager.SetMetadata("pathMapper", "AdministrationConfig");

// add the module in the moduleProviders section
AddModuleProvider(adminManager, "myIISModule", "myIISModuleUI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=YourPublicKey");

// add the module in the modules section
AddModule(adminManager, "myIISModule");

// commit changes
adminManager.CommitChanges();

function AddModuleProvider(adminManager, name, type) {
    var moduleProvidersSection = adminManager.GetAdminSection("moduleProviders", "MACHINE/WEBROOT");

    var moduleProviders = moduleProvidersSection.Collection;

    // if already exists, do nothing
    var addElementPos = FindElement(moduleProviders, "add", ["name", name]);
    if (addElementPos != -1) return;

    var moduleProvider = moduleProviders.CreateNewElement("add");
    moduleProvider.Properties.Item("name").Value = name;
    moduleProvider.Properties.Item("type").Value = type;

    moduleProviders.AddElement(moduleProvider);
}

// if already exists, do nothing
function AddModule(adminManager, name) {
    var modulesSection = adminManager.GetAdminSection("modules", "MACHINE/WEBROOT");

    var modules = modulesSection.Collection;

    // See if already exists
    var addElementPos = FindElement(modules, "add", ["name", name]);
    if (addElementPos != -1) return;

    var module = modules.CreateNewElement("add");
    module.Properties.Item("name").Value = name;

    modules.AddElement(module);
}

// Helper function to find an element in a collection based on the specified attributes
function FindElement(collection, elementTagName, valuesToMatch) {
    for (var i = 0; i < collection.Count; i++) {
        var element = collection.Item(i);

        if (element.Name == elementTagName) {
            var matches = true;
            for (var iVal = 0; iVal < valuesToMatch.length; iVal += 2) {
                var property = element.GetPropertyByName(valuesToMatch[iVal]);
                var value = property.Value;
                if (value != null) {
                    value = value.toString();
                }
                if (value != valuesToMatch[iVal + 1]) {
                    matches = false;
                    break;
                }
            }
            if (matches) {
                return i;
            }
        }
    }

    return -1;
}

I'll use this time to also mention that it is very important to add it to the Modules section in case you want your module to be used from Site and Application delegated connections, otherwise only Server connections will get them.