PdIISManager

PdIISManager

using System;
using System.Linq;
using System.Windows.Forms;
using System.Collections.Generic;
using Microsoft.Web.Administration;


namespace PdMagic.Windows
{
    public class VirtualFolder
    {
        public VirtualFolder(string aAlias, string aPhysicalFolder)
        {
            Alias = aAlias;
            PhysicalFolder = aPhysicalFolder;
        }
        public string Alias { get; set; }
        public string PhysicalFolder { get; set; }
    }
    public class MimeEntry
    {
        public MimeEntry(string aExtension, string aMIMEType)
        {
            Extension = aExtension;
            MimeType = aMIMEType;
        }
        public string Extension { get; set; }
        public string MimeType { get; set; }
    }

    public class PdIISManager
    {
        private ServerManager mServerManager;

        public PdIISManager( )
        {
            mServerManager = new ServerManager();
        }

        public void ReLoad()
        {
            mServerManager = new ServerManager();
        }
        public SiteCollection Sites
        {
            get { return mServerManager.Sites; }
        }

        public ApplicationPoolCollection ApplicationPools
        {
            get { return mServerManager.ApplicationPools; }
        }

        public void AddNewSite(string aName, string aFolder, List<string> aStatus)
        {
            aStatus.Add("NEW SITE");
            try
            {
                // Create and add site
                const string lProtocol = "http";
                const string lBinding = "*:80:";
                mServerManager.Sites.Add(aName, lProtocol, lBinding, aFolder);
                mServerManager.CommitChanges();

                aStatus.Add($"+ Name: ({aName})");
                aStatus.Add($"+ Protocol: ({lProtocol}), binding: ({lBinding})");
            }
            catch (Exception lAddNewSite)
            {
                throw new Exception("AddNewSite", lAddNewSite);
            }
        }

        public void DeleteSite(string aName, List<string> aStatus)
        {
            aStatus.Add("DELETE SITE");
            try
            {
                var lSite = mServerManager.Sites[aName];
                mServerManager.Sites.Remove(lSite);
                mServerManager.CommitChanges();
                aStatus.Add($"+ Name: ({aName})");
            }
            catch (Exception lDeleteSite)
            {
                throw new Exception( "DeleteSite", lDeleteSite);
            }
        }
        public void VerifyDLLAllowed(string aName, string aDLLPath, string aDescription, List<string> aStatus)
        {
            aStatus.Add("NEW ISAPI CGI RESTRICTION");

            const string lSection = "system.webServer/security/isapiCgiRestriction";
            var lConfig = mServerManager.GetApplicationHostConfiguration();
            var lIsapiCgiRestrictionSection = lConfig.GetSection(lSection);
            ConfigurationElementCollection lIsapiCgiRestrictionCollection = lIsapiCgiRestrictionSection.GetCollection();
            aStatus.Add( $"* Section: ({lSection})");

            var lExists = lIsapiCgiRestrictionCollection.Any(
                aConfigurationElement => aConfigurationElement.Attributes["path"].Value.Equals(aDLLPath));

            if (lExists)
            {
                aStatus.Add($"= An element already exists that points to ({aDLLPath})");
            }
            else
            {
                ConfigurationElement lAddElement = lIsapiCgiRestrictionCollection.CreateElement("add");
                lAddElement["groupId"] = aName;
                lAddElement["path"] = aDLLPath;
                lAddElement["allowed"] = true;
                lAddElement["description"] = aDescription;
                lIsapiCgiRestrictionCollection.Add(lAddElement);
                mServerManager.CommitChanges();

                aStatus.Add($"+ GroupId: ({lAddElement["groupId"]})");
                aStatus.Add($"+ Path=({lAddElement["path"]})");
                aStatus.Add($"+ Allowed=({lAddElement["allowed"]})");
                aStatus.Add($"+ Description=({lAddElement["description"]})");
            }
        }

        public void CreateISAPIHandler(string aSiteName, string aVirtualPath,string aHandlerName, string aDLLPath, List<string> aStatus)
        {
            aStatus.Add("ADD ISAPI HANDLER");
            var lParams = $"(SiteName={aSiteName}, VirtualPath={aVirtualPath}, Handler={aHandlerName}, DllPath={aDLLPath})";
            try
            {
                Configuration lSiteConfig;
                ConfigurationSection lHandlersSection;
                ConfigurationElementCollection lHandlersCollection;
                bool lExists;

                //var lSiteConfig = mServerManager.GetApplicationHostConfiguration();
                try
                {
                    lSiteConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath);
                    aStatus.Add($"* Site / Path: ({aSiteName}{aVirtualPath})");
                }
                catch (Exception lGetWebConfiguration)
                {
                    throw new Exception("GetWebConfiguration()", lGetWebConfiguration);
                }

                try
                {
                    const string lSection = "system.webServer/handlers";
                    const string lPolicy = "Read, Script, Execute";
                    lHandlersSection = lSiteConfig.GetSection(lSection);
                    lHandlersSection["accessPolicy"] = lPolicy;
                    aStatus.Add($"* Set {lSection}/accessPolicy to ({lPolicy})");
                }
                catch (Exception lGetSection)
                {
                    throw new Exception("GetSection() and set accessPolicy", lGetSection);
                }

                try
                {
                    lHandlersCollection = lHandlersSection.GetCollection();
                }
                catch (Exception lGetCollection)
                {
                    throw new Exception("GetCollection()", lGetCollection);
                }

                try
                {
                    lExists = lHandlersCollection.Any(
                        aConfigurationElement => aConfigurationElement.Attributes["name"].Value.Equals(aHandlerName));
                }
                catch (Exception lCheckExists)
                {
                    throw new Exception("Check Handler Exists", lCheckExists);
                }

                if (lExists)
                {
                    aStatus.Add($"= Handler: ({aHandlerName}) already exists");
                }
                else
                {
                    try
                    {
                        ConfigurationElement lAddElement = lHandlersCollection.CreateElement("add");
                        lAddElement["name"] = aHandlerName;

                        lAddElement["path"] = "CrashMagicOnline_ISAPI.dll";
                        lAddElement["allowPathInfo"] = "true";

                        lAddElement["verb"] = "*";
                        lAddElement["modules"] = "IsapiModule";
                        lAddElement["scriptProcessor"] = aDLLPath;
                        lAddElement["resourceType"] = "File";
                        lAddElement["requireAccess"] = "Execute";
                        lAddElement["preCondition"] = "bitness32";
                        lHandlersCollection.Add(lAddElement);
                        mServerManager.CommitChanges();

                        aStatus.Add($"+ name: ({lAddElement["name"]})");
                        aStatus.Add($"+ path: ({ lAddElement["path"]})");
                        aStatus.Add($"+ allowPathInfo: ({ lAddElement["allowPathInfo"]})");
                        aStatus.Add($"+ verb: ({ lAddElement["verb"]})");
                        aStatus.Add($"+ modules: ({ lAddElement["modules"]})");
                        aStatus.Add($"+ scriptProcessor: ({ lAddElement["scriptProcessor"]})");
                        aStatus.Add($"+ resourceType: ({ lAddElement["resourceType"]})");
                        aStatus.Add($"+ requireAccess: ({ lAddElement["requireAccess"]})");
                        aStatus.Add($"+ preCondition: ({ lAddElement["preCondition"]})");
                    }
                    catch (Exception lAddHandler)
                    {
                        throw new Exception("Add Handler", lAddHandler);
                    }
                }
            }
            catch (Exception lException)
            {
               throw new Exception($"CreateISAPIHandler{lParams}", lException);   
            }
        }

        public void SetMaxAllowedContentLength(string aSiteName, int aLength, List<string> aStatus)

        {
            aStatus.Add("SET MAX ALLOWED CONTENT LENGTH");
            const string lSectionPath = "system.webServer/security/requestFiltering";
            var lStatus = new List<string>();

            // Unlock section:
            var lConf = mServerManager.GetApplicationHostConfiguration();
            var lSection = lConf.RootSectionGroup.SectionGroups["system.webServer"].SectionGroups["security"].Sections["requestFiltering"];
            lSection.OverrideModeDefault = "Allow";
            mServerManager.CommitChanges();
            aStatus.Add($"* Section: ({lSectionPath}) Set OverrideModeDefault to (Allow).");

            // Set value:
            var lConfig = mServerManager.GetWebConfiguration(aSiteName);
            var lRequestFilteringSection = lConfig.GetSection(lSectionPath);
            var lRequestLimitsElement = lRequestFilteringSection.GetChildElement("requestLimits");
            var lOldLength = Convert.ToInt64(lRequestLimitsElement.GetAttributeValue("maxAllowedContentLength"));
            if (lOldLength == aLength)
            {
                aStatus.Add($"= requestLimits/maxAllowedContentLength already set to ({lOldLength})");
            }
            else
            {
                lRequestLimitsElement.SetAttributeValue("maxAllowedContentLength", aLength);
                mServerManager.CommitChanges();

                aStatus.Add($"+ Set requestLimits/maxAllowedContentLength to ({lRequestLimitsElement.GetAttributeValue("maxAllowedContentLength")})");
            }
        }

        public void SetServerRuntimeValues(string aSiteName, uint aUploadReadAheadSize, uint aMaxRequestEntityAllowed, List<string> aStatus)
        {
            aStatus.Add("SET SERVER RUNTIME PARAMETERS");
            const string lSectionPath = "system.webServer/serverRuntime";
            // Unlock section:
            var lConf = mServerManager.GetApplicationHostConfiguration();
            var lSection = lConf.RootSectionGroup.SectionGroups["system.webServer"].Sections["serverRuntime"];
            lSection.OverrideModeDefault = "Allow";
            mServerManager.CommitChanges();

            aStatus.Add($"* Section ({lSectionPath}) Set OverrideModeDefault to (Allow).");

            // Set value:
            var lConfig = mServerManager.GetWebConfiguration(aSiteName);
            var lServerRuntimeSection = lConfig.GetSection(lSectionPath);

            var lOldReadAheadSize = Convert.ToInt64(lServerRuntimeSection.GetAttributeValue("uploadReadAheadSize"));
            if (lOldReadAheadSize == aUploadReadAheadSize)
            {
                aStatus.Add($"= uploadReadAheadSize already set to ({lOldReadAheadSize})");
            }
            else
            {
                lServerRuntimeSection.SetAttributeValue("uploadReadAheadSize", aUploadReadAheadSize);
                aStatus.Add($"+ Set uploadReadAheadSize: ({lServerRuntimeSection.GetAttributeValue("uploadReadAheadSize")})");
            }

            var lOldMaxRequestEntity = Convert.ToInt64(lServerRuntimeSection.GetAttributeValue("maxRequestEntityAllowed"));
            if (lOldMaxRequestEntity == aMaxRequestEntityAllowed) {
                aStatus.Add($"= uploadReadAheadSize already set to ({lOldMaxRequestEntity})");
            }
            else
            {
                lServerRuntimeSection.SetAttributeValue("maxRequestEntityAllowed", aMaxRequestEntityAllowed);
                mServerManager.CommitChanges();

                aStatus.Add($"+ Set maxRequestEntityAllowed: ({lServerRuntimeSection.GetAttributeValue("maxRequestEntityAllowed")})");
            }
        }

        public void VerifyDefaultDocument(string aSiteName, string aVirtualPath, string aFileName, List<string> aStatus)
        {
            aStatus.Add("SET DEFAULT DOCUMENT");

            const string lSectionPath = "system.webServer/defaultDocument";
            var lConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath);
            var lDefaultDocumentSection = lConfig.GetSection(lSectionPath);
            lDefaultDocumentSection["enabled"] = true;

            aStatus.Add($"* Section: ({lSectionPath}) Set enabled = true");
            aStatus.Add($"* Site / Path: ({aSiteName}{aVirtualPath})");

            var lExists = false;
            var lFilesCollection = lDefaultDocumentSection.GetCollection("files");
            foreach (var lDefaultPage in lFilesCollection)
            {
                if (aFileName.ToLower() == ((string)lDefaultPage["value"]).ToLower())
                    lExists = true;
            }

            if (lExists)
            {
                aStatus.Add($"= ({aFileName}) already exists as default");
            }
            else
            {
                ConfigurationElement lAddElement = lFilesCollection.CreateElement("add");
                lAddElement["value"] = aFileName;
                lFilesCollection.AddAt(0, lAddElement);
                mServerManager.CommitChanges();

                aStatus.Add($"+ Inserted ({aFileName}) as the first default document");
            }
        }

        public bool MimeTypeRegistered(string aSiteName, string aVirtualPath, string aExtension, string aMimeType)
        {
            bool lExists = false;

            if (aVirtualPath != "/")
                lExists = MimeTypeRegistered(aSiteName, "/", aExtension, aMimeType);

            if (!lExists)
            {
                var lVDirConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath);
                var lStaticContentSection = lVDirConfig.GetSection("system.webServer/staticContent");
                var lMimeMap = lStaticContentSection.GetCollection();

                var lMt =
                    lMimeMap.FirstOrDefault(
                        aMapEntry => (string) aMapEntry.Attributes["fileExtension"].Value == aExtension);
                lExists = lMt != null;

            }

            return lExists;
        }

        public void VerifyMimeType(string aSiteName, string aVirtualPath, string aExtension, string aMimeType, List<string> aStatus)
        {
            const string lSectionPath = "system.webServer/staticContent";
            if (MimeTypeRegistered(aSiteName, aVirtualPath, aExtension, aMimeType))
            {
                aStatus.Add($"= Mime entry already exists for ({aExtension})");
            }
            else
            {
                var lVDirConfig = mServerManager.GetWebConfiguration(aSiteName, aVirtualPath);
                var lStaticContentSection = lVDirConfig.GetSection(lSectionPath);
                var lMimeMap = lStaticContentSection.GetCollection();

                var lMimeMapElement = lMimeMap.CreateElement("mimeMap");
                lMimeMapElement["fileExtension"] = aExtension;
                lMimeMapElement["mimeType"] = aMimeType;
                lMimeMap.Add(lMimeMapElement);
                mServerManager.CommitChanges();

                aStatus.Add($"+ Added mime type: ({aMimeType}) for ({aExtension})");
            }
        }

        public void VerifyMimeTypes(string aSiteName, string aApplicationPath, List<MimeEntry> aMimeEntries, List<string> aStatus)
        {
            const string lSectionPath = "system.webServer/staticContent";
            aStatus.Add("SET MIME TYPES");
            aStatus.Add($"* Section: ({lSectionPath})");
            aStatus.Add($"* Site / Path: ({aSiteName}{aApplicationPath})");

            foreach (MimeEntry lEntry in aMimeEntries)
            {
                VerifyMimeType(aSiteName, aApplicationPath, lEntry.Extension, lEntry.MimeType, aStatus);
            }
        }

    private static ConfigurationElement FindElement(ConfigurationElementCollection aCollection, string aElementTagName, params string[] aKeyValues)
        {
            foreach (ConfigurationElement lElement in aCollection)
            {
                if (String.Equals(lElement.ElementTagName, aElementTagName, StringComparison.OrdinalIgnoreCase))
                {
                    bool lMatches = true;
                    for (int i = 0; i < aKeyValues.Length; i += 2)
                    {
                        object o = lElement.GetAttributeValue(aKeyValues[i]);
                        string lValue = null;
                        if (o != null)
                        {
                            lValue = o.ToString();
                        }
                        if (!String.Equals(lValue, aKeyValues[i + 1], StringComparison.OrdinalIgnoreCase))
                        {
                            lMatches = false;
                            break;
                        }
                    }
                    if (lMatches)
                    {
                        return lElement;
                    }
                }
            }
            return null;
        }

        public void SetApplicationUser(string aSite, string aApplication, string aUserName, string aPassword, List<string> aStatus)
        {
            aStatus.Add("SET APPLICATION USER");
            try
            {
                const string lSectionPath = "system.applicationHost/sites";
                var lConfig = mServerManager.GetApplicationHostConfiguration();
                var lSitesSection = lConfig.GetSection(lSectionPath);
                var lSitesCollection = lSitesSection.GetCollection();
                var lSiteElement = FindElement(lSitesCollection, "site", "name", aSite);
                var lApplicationCollection = lSiteElement.GetCollection();

                ConfigurationElement lApplicationElement = FindElement(lApplicationCollection, "application", "path", aApplication);
                ConfigurationElementCollection lVirtualDirCollection = lApplicationElement.GetCollection();
                ConfigurationElement lVirtualDirElement = FindElement(lVirtualDirCollection, "virtualDirectory", "path", @"/");
                aStatus.Add($"* Application: ({aApplication})");
                aStatus.Add($"* Site: ({aSite})");

                if (lVirtualDirElement.Attributes["userName"].Value.Equals(aUserName))
                {
                    aStatus.Add($"= UserName: ({lVirtualDirElement.Attributes["userName"].Value}) already set");
                }
                else
                {
                    lVirtualDirElement.Attributes["userName"].Value = aUserName;
                    lVirtualDirElement.Attributes["password"].Value = aPassword;
                    aStatus.Add($"+ Set userName: ({lVirtualDirElement.Attributes["userName"].Value})");
                    aStatus.Add($"+ Set password: (***)");
                }
            }
            catch (Exception lSetApplicationUser)
            {
                throw new Exception("SetApplicationUser", lSetApplicationUser);
            }
        }

        public void AddNewApplication(string aSite, string aApplication, string aPath, List<string> aStatus)
        {
            aStatus.Add("ADD APPLICATION");
            try
            {
                mServerManager.Sites[aSite].Applications.Add(aApplication, aPath);
                mServerManager.CommitChanges();
                aStatus.Add($"+ Site / Path: ({ aSite}{aPath})");
                aStatus.Add($"+ Application: ({aApplication})"); 
            }
            catch (Exception lAddNewApplication)
            {
                throw new Exception("Add New Application", lAddNewApplication);
            }
        }


        private void VerifyVirtualDirectory(string aSite, string aApplication, string aVirtualName, string aPhysicalDir, List<string> aStatus )
        {
            try
            {
                var lExists = false;
                var lApplication = mServerManager.Sites[aSite].Applications[aApplication];
                foreach (var lDirectory in lApplication.VirtualDirectories)
                {
                    if (lDirectory.PhysicalPath.ToLower() == aPhysicalDir.ToLower())
                        lExists = true;
                }

                if (lExists)
                {
                    aStatus.Add($"= Virtual directory ({aVirtualName}) already exists");
                }
                else
                {
                    lApplication.VirtualDirectories.Add(aVirtualName, aPhysicalDir);
                    mServerManager.CommitChanges();

                    aStatus.Add($"+ Added virtual directory ({aVirtualName}={aPhysicalDir})");
                }
            }
            catch (Exception lAddNewVirtualDirectory)
            {
                throw new Exception("Add New Virtual Directory ", lAddNewVirtualDirectory);
            }
        }

        public void VerifyVirtualFolders( string aSiteName, string aApplicationPath, List<VirtualFolder> aFolders, List<string> aStatus)
        {
            aStatus.Add($"ADD VIRTUAL FOLDERS");
            aStatus.Add($"* Site / Path: ({aSiteName}{aApplicationPath})");
            foreach (VirtualFolder lVirtualFolder in aFolders)
            {
                VerifyVirtualDirectory( aSiteName, aApplicationPath, $"/{lVirtualFolder.Alias}",
                    lVirtualFolder.PhysicalFolder, aStatus);
            }
        }
        public void SetUpApplicationPool(string aApplicationPoolName, string aUserName, string aPassword, List<string> aStatus)
        {
            aStatus.Add("PREPARE APPLICATION POOL");
            try
            {
                aStatus.Add($"* Pool name: ({aApplicationPoolName})");

                var lAppPool = mServerManager.ApplicationPools[aApplicationPoolName];
                lAppPool.ManagedRuntimeVersion = "v4.0";
                aStatus.Add($"+ Set ManagedRuntimeVersion: ({lAppPool.ManagedRuntimeVersion})");

                lAppPool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
                aStatus.Add($"+ Set ManagedPipelineMode: ({lAppPool.ManagedPipelineMode})");

                lAppPool.Enable32BitAppOnWin64 = true;
                aStatus.Add($"+ Set Enable32BitAppOnWin64: ({lAppPool.Enable32BitAppOnWin64})");

                lAppPool.AutoStart = true;
                aStatus.Add($"+ Set AutoStart: ({lAppPool.AutoStart})");

                lAppPool.ProcessModel.IdleTimeout = new TimeSpan(0, 360, 0);
                aStatus.Add($"+ Set ProcessModel.IdleTimeout: ({lAppPool.ProcessModel.IdleTimeout})");

                lAppPool.Recycling.DisallowOverlappingRotation = true;
                aStatus.Add($"+ Set Recycling.DisallowoverlappingRotation: ({lAppPool.Recycling.DisallowOverlappingRotation})");

                lAppPool.Recycling.PeriodicRestart.Time = new TimeSpan(0, 0, 0);
                aStatus.Add($"+ Set Recycling.PeriodicRestart.Time: ({new TimeSpan(0, 0, 0)})");

                lAppPool.Recycling.PeriodicRestart.Schedule.Clear();
                lAppPool.Recycling.PeriodicRestart.Schedule.Add(new TimeSpan(3,0,0));
                aStatus.Add($"+ Set Recycling.PeriodicRestart.Schedule: ({new TimeSpan(3,0,0)})");
                
                if (aUserName != string.Empty)
                {
                    lAppPool.ProcessModel.UserName = Environment.MachineName + "\\" + aUserName;
                    lAppPool.ProcessModel.IdentityType = ProcessModelIdentityType.SpecificUser;
                    lAppPool.ProcessModel.Password = aPassword;
                    aStatus.Add($"+ Set ProcessModelUserName: ({lAppPool.ProcessModel.UserName}) Password: (***)");
                    aStatus.Add($"+ Set IdentityType: (SpecificUser)");
                }
                else
                {
                    aStatus.Add("* No User Name sent");
                }
                mServerManager.CommitChanges();
            }

            catch (Exception lSetUpApplicationPool)
            {
                throw new Exception("Set Up ApplicationPool", lSetUpApplicationPool);
            }
        }

        public void AddNewApplicationPool(string aApplicationPoolName, List<string> aStatus)
        {
            aStatus.Add("ADD APPLICATION POOL");
            try
            {
                mServerManager.ApplicationPools.Add(aApplicationPoolName);
                mServerManager.CommitChanges();
                aStatus.Add($"+ Pool name: ({aApplicationPoolName})");

            }
            catch (Exception lAddNewApplicationPool)
            {
                throw new Exception("Add New ApplicationPool", lAddNewApplicationPool);
            }
        }

        public void DeleteApplicationPool(string aApplicationPoolName, List<string> aStatus)
        {
            aStatus.Add("DELETE APPLICATION POOL");
            try
            {
                ApplicationPool lAppPool = mServerManager.ApplicationPools[aApplicationPoolName];
                if (lAppPool == null)
                {
                    throw new Exception("DeleteApplicationPool - Application pool not found");
                }

                ApplicationPoolCollection lAppColl = mServerManager.ApplicationPools;
                lAppColl.Remove(lAppPool);
                mServerManager.CommitChanges();
                aStatus.Add($"+ Pool name: ({aApplicationPoolName})");
            }
            catch (Exception lDeleteApplication)
            {
                throw new Exception("Delete Application", lDeleteApplication);
            }
        }

        public void AttachSiteToApplicationPool(string aSite, string aApplicationPath, string aApplicationPool, List<string> aStatus)
        {
            aStatus.Add("ADD SITE TO APPLICATION POOL");
            try
            {
                mServerManager.Sites[aSite].Applications[aApplicationPath].ApplicationPoolName = aApplicationPool;
                ApplicationPool lAppPool = mServerManager.ApplicationPools[aApplicationPool];
                aStatus.Add($"+ Site: ({mServerManager.Sites[aSite].Name}) added to pool: ({lAppPool.Name})");

                mServerManager.CommitChanges();
            }
            catch (Exception lAttachSiteToAppPool)
            {
                throw new Exception("Attach Site To Application Pool", lAttachSiteToAppPool);
            }
        }

    }
}