// ----------------------------------------------------------------------------------------------------------
// This script is to fix a setup issue for WCF when .NET 3.5 is installed or uninstalled in different orders
// multiple times. Here is a typical symptom. A .NET applicaiton would faile with the following error:
//     System.Configuration.ConfigurationErrorsException: Unrecognized configuration section 
//     system.serviceModel. (c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Config\machine.config line 146)
//
// To fix the issue, you need to save this script locally and run the following command:
//     cscript FixServiceModel30Reg.js
//
// ----------------------------------------------------------------------------------------------------------
var g_wshShell = WScript.CreateObject("WScript.Shell");
var g_wshEnv = g_wshShell.Environment("PROCESS");
var g_oFSO = new ActiveXObject("Scripting.FileSystemObject");
var machineConfigPath = null;
var machineConfigPath64 = null;
var net30IsInstalled = false;
var g_is64Bit = 0;

/*
// Inserting the following Xml into the broken machine.config files
		<sectionGroup name="system.runtime.serialization" type="System.Runtime.Serialization.Configuration.SerializationSectionGroup, System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
			<section name="dataContractSerializer" type="System.Runtime.Serialization.Configuration.DataContractSerializerSection, System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
		</sectionGroup>
		<sectionGroup name="system.serviceModel" type="System.ServiceModel.Configuration.ServiceModelSectionGroup, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
			<section name="behaviors" type="System.ServiceModel.Configuration.BehaviorsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="bindings" type="System.ServiceModel.Configuration.BindingsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="client" type="System.ServiceModel.Configuration.ClientSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="comContracts" type="System.ServiceModel.Configuration.ComContractsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="commonBehaviors" type="System.ServiceModel.Configuration.CommonBehaviorsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowDefinition="MachineOnly" allowExeDefinition="MachineOnly"/>
			<section name="diagnostics" type="System.ServiceModel.Configuration.DiagnosticSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="extensions" type="System.ServiceModel.Configuration.ExtensionsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="machineSettings" type="System.ServiceModel.Configuration.MachineSettingsSection, SMDiagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowDefinition="MachineOnly" allowExeDefinition="MachineOnly"/>
			<section name="serviceHostingEnvironment" type="System.ServiceModel.Configuration.ServiceHostingEnvironmentSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="services" type="System.ServiceModel.Configuration.ServicesSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
		</sectionGroup>
		<sectionGroup name="system.serviceModel.activation" type="System.ServiceModel.Activation.Configuration.ServiceModelActivationSectionGroup, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
			<section name="diagnostics" type="System.ServiceModel.Activation.Configuration.DiagnosticSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="net.pipe" type="System.ServiceModel.Activation.Configuration.NetPipeSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
			<section name="net.tcp" type="System.ServiceModel.Activation.Configuration.NetTcpSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
		</sectionGroup>
*/

var serializationGroup = new Array(
    new Array("system.runtime.serialization", "System.Runtime.Serialization.Configuration.SerializationSectionGroup, System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("dataContractSerializer", "System.Runtime.Serialization.Configuration.DataContractSerializerSection, System.Runtime.Serialization, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
);

var serviceModelGroup = new Array(
    new Array("system.serviceModel", "System.ServiceModel.Configuration.ServiceModelSectionGroup, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("behaviors", "System.ServiceModel.Configuration.BehaviorsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("bindings", "System.ServiceModel.Configuration.BindingsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("client", "System.ServiceModel.Configuration.ClientSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("comContracts", "System.ServiceModel.Configuration.ComContractsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("commonBehaviors", "System.ServiceModel.Configuration.CommonBehaviorsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "MachineOnly", "MachineOnly"),
    new Array("diagnostics", "System.ServiceModel.Configuration.DiagnosticSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("extensions", "System.ServiceModel.Configuration.ExtensionsSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("machineSettings", "System.ServiceModel.Configuration.MachineSettingsSection, SMDiagnostics, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089", "MachineOnly", "MachineOnly"),
    new Array("serviceHostingEnvironment", "System.ServiceModel.Configuration.ServiceHostingEnvironmentSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("services", "System.ServiceModel.Configuration.ServicesSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
);

var serviceModelActivationGroup = new Array(
    new Array("system.serviceModel.activation", "System.ServiceModel.Activation.Configuration.ServiceModelActivationSectionGroup, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("diagnostics", "System.ServiceModel.Activation.Configuration.DiagnosticSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("net.pipe", "System.ServiceModel.Activation.Configuration.NetPipeSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"),
    new Array("net.tcp", "System.ServiceModel.Activation.Configuration.NetTcpSection, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
);

function Main() {
    InitializePaths();

    if (machineConfigPath != null) {
        FixMachineConfigForWCF(machineConfigPath);
    }

    if (machineConfigPath64 != null) {
        FixMachineConfigForWCF(machineConfigPath64);
    }
}

function InitializePaths() {
    var fxPath = g_wshShell.ExpandEnvironmentStrings("%windir%\\Microsoft.Net");
    machineConfigPath = fxPath + "\\Framework\\v2.0.50727\\config\\machine.config";
    if (!g_oFSO.FileExists(machineConfigPath)) {
        Warn("Path '" + machineConfigPath + "' does not exist!");
        machineConfigPath = null;
    }

    if ((g_wshEnv("PROCESSOR_ARCHITECTURE").toLowerCase() != "x86") || (undefined != g_wshEnv("PROCESSOR_ARCHITEW6432"))) {
        g_is64Bit = 1;
        machineConfigPath64 = fxPath + "\\Framework64\\v2.0.50727\\config\\machine.config";
        if (!g_oFSO.FileExists(machineConfigPath64)) {
            Warn("Path '" + machineConfigPath64 + "' does not exist!");
            machineConfigPath64 = null;
        }
    }

    if (g_oFSO.FolderExists(fxPath + "\\Framework\\v3.0\\Windows Communication Foundation")) {
        WScript.Echo("Found 3.0 on the box");
        net30IsInstalled = true;
    }
}

function Log(msg)
{
    WScript.Echo(msg);
}

function Warn(msg) {
    WScript.Echo("WARNING: " + msg);
}

function Error(msg)
{
    WScript.Echo("ERROR: " + msg);
    WScript.Quit(1);
}

function CreateTempFile() {
   var folder, fileName, TemporaryFolder = 2;
   folder = g_oFSO.GetSpecialFolder(TemporaryFolder);
   return folder.Path + "\\" + g_oFSO.GetTempName();
}

function RemoveExistingSections(configSectionNode) {
    var node = configSectionNode.selectSingleNode("//sectionGroup[@name='system.runtime.serialization']");
    if (node != null) {
        configSectionNode.removeChild(node);
    }

    node = configSectionNode.selectSingleNode("//sectionGroup[@name='system.serviceModel']");
    if (node != null) {
        configSectionNode.removeChild(node);
    }

    node = configSectionNode.selectSingleNode("//sectionGroup[@name='system.serviceModel.activation']");
    if (node != null) {
        configSectionNode.removeChild(node);
    }
}

function FixConfigSource(root) {
    var node = root.selectSingleNode("system.serviceModel/client");
    RemoveChildNodesForConfigSource(node);

    node = root.selectSingleNode("system.serviceModel/extensions");
    RemoveChildNodesForConfigSource(node);

    node = root.selectSingleNode("system.serviceModel/commonBehaviors");
    RemoveChildNodesForConfigSource(node);
}

function RemoveChildNodesForConfigSource(node) {
    var configSource = null;
    if (node != null) {
        configSource = node.getAttribute("configSource");
    }

    if (configSource != null) {
        var length = node.childNodes.length;
        for (var i = length - 1; i >= 0; i--) {
            node.removeChild(node.childNodes.item(i));
        }
    }
}

function RemoveSystemServiceModelSection(root) {
    var node = root.selectSingleNode("system.serviceModel");
    if (node != null) {
        root.removeChild(node);
        WScript.Echo("Removing dangling 'system.serviceModel' node");
    }
}

function AddOneSectionGroup(xmlDoc, element, groupArray) {
    element.setAttribute("name", groupArray[0][0]);
    element.setAttribute("type", groupArray[0][1]);

    var childElement;
    for (var i = 1; i < groupArray.length; i++) {
        AddTextNode(xmlDoc, element, "\r\n\t\t\t");

        childElement = xmlDoc.createElement("section");
        element.appendChild(childElement);
        childElement.setAttribute("name", groupArray[i][0]);
        childElement.setAttribute("type", groupArray[i][1]);
        if (groupArray[i].length > 2) {
            childElement.setAttribute("allowDefinition", groupArray[i][2]);
            childElement.setAttribute("allowExeDefinition", groupArray[i][3]);
        }
    }

    AddTextNode(xmlDoc, element, "\r\n\t\t");
}

function AddTextNode(xmlDoc, element, text) {
    var textNode = xmlDoc.createTextNode(text);
    element.appendChild(textNode);
}

function AddWCFSections(xmlDoc, configSectionNode) {
    Log("Adding serialization section group...");
    var newElement = xmlDoc.createElement("sectionGroup");
    AddOneSectionGroup(xmlDoc, newElement, serializationGroup);
    configSectionNode.appendChild(newElement);

    Log("Adding serviceModel section group...");
    AddTextNode(xmlDoc, configSectionNode, "\r\n\t\t");
    newElement = xmlDoc.createElement("sectionGroup");
    AddOneSectionGroup(xmlDoc, newElement, serviceModelGroup);
    configSectionNode.appendChild(newElement);

    Log("Adding serviceModel.activation section group...");
    AddTextNode(xmlDoc, configSectionNode, "\r\n\t\t");
    newElement = xmlDoc.createElement("sectionGroup");
    AddOneSectionGroup(xmlDoc, newElement, serviceModelActivationGroup);
    configSectionNode.appendChild(newElement);

    AddTextNode(xmlDoc, configSectionNode, "\r\n\t");
}

function FixMachineConfigForWCF(configPath) {
    var xmlDoc = null;
    var xmlParseError;
    var node;

    var tempFilePath = CreateTempFile();

    Log("Copying file: " + configPath + " -> " + tempFilePath);
    try {
        if (g_oFSO.FileExists(tempFilePath)) {
            g_oFSO.DeleteFile(tempFilePath, true);
        }

        g_oFSO.CopyFile(configPath, tempFilePath);
    } catch (e) {
        Error(FormatErrorString(e));
    }


    Log("Loading xml file: " + tempFilePath);
    try {
        xmlDoc = new ActiveXObject("MSXML2.DOMDocument");
    } catch (e) {
        Error(FormatErrorString(e));
    }

    Log("Fixing xml file: " + tempFilePath);
    try {
        xmlDoc.validateOnParse = "false";
        xmlDoc.async = false;
        xmlDoc.resolveExternals = true;
        xmlDoc.preserveWhiteSpace = false;
        xmlDoc.load(tempFilePath);

        var configSectionNode = xmlDoc.documentElement.selectSingleNode("//configuration//configSections");
        if (configSectionNode == null) {
            Error("Cannot find the configuration element '/configuration/configSections' in " + configPath);
        }

        if (net30IsInstalled) {
            RemoveExistingSections(configSectionNode);
            AddWCFSections(xmlDoc, configSectionNode);
            FixConfigSource(xmlDoc.documentElement);
        }
        else {
            RemoveSystemServiceModelSection(xmlDoc.documentElement);
        }

        xmlDoc.save(tempFilePath);
    } catch (e) {
    throw e;
        xmlParseError = xmlDoc.parseError;

        if (IsValid(xmlParseError.reason)) {
            Error(xmlParseError.url + ":" + xmlParseError.line + "  " + xmlParseError.reason);
        }
        else {
            Error(FormatErrorString(e));
        }
    }

    Log("Copying file: " + tempFilePath + " -> " + configPath);

    try {
        g_oFSO.CopyFile(tempFilePath, configPath, true);
        g_oFSO.DeleteFile(tempFilePath, true);
    } catch (e) {
        Error(FormatErrorString(e));
    }
}

function IsNotValid(variable) {
    try {
        return (variable == null ||
                variable === "" ||
                variable != variable);
    } catch (e) {
        return (variable == null);
    }
}

function IsValid(variable) {
    return (!IsNotValid(variable));
}

function FormatErrorString(errorObject) {
    if (IsValid(errorObject) && IsValid(errorObject.number)) {
        return "(" + Int32ToHRESULT(errorObject.number) + ")" + ": " + errorObject.description;
    }

    return errorObject;
}

function Int32ToHRESULT(num) {
    if (num < 0) {
        return "0x" + new Number(0x100000000 + num).toString(16);
    }

    return "0x" + num.toString(16);
}

Main();