using System;
using System.DirectoryServices;
using System.Globalization;
using Ada.Configurator.Common;
using NAnt.Core.Attributes;
using NAnt.Core;

namespace AdaNantTasks
{
    [TaskName("createWebSite")]
    public class CreateWebsiteTask : Task
    {
        public NantLogger logger = new NantLogger();

        private string m_server;
        [TaskAttribute("server", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string Server
        {
            get { return m_server; }
            set { m_server = value; }
        }

        private string m_websiteName;
        [TaskAttribute("websiteName", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string WebsiteName
        {
            get { return m_websiteName; }
            set { m_websiteName = value; }
        }

        private string m_binding;
        [TaskAttribute("binding", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string Binding
        {
            get { return m_binding; }
            set { m_binding = value; }
        }

        private string m_webFolder;
        [TaskAttribute("webFolder", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string WebFolder
        {
            get { return m_webFolder; }
            set { m_webFolder = value; }
        }

        private string m_appPool;
        [TaskAttribute("appPool", Required = true)]
        [StringValidator(AllowEmpty = false)]
        public string AppPool
        {
            get { return m_appPool; }
            set { m_appPool = value; }
        }

        /// <summary>
        /// Creates website
        /// </summary>
        protected override void ExecuteTask()
        {
            try
            {
                int result = CreateWebsite();
                switch (result)
                {
                    case 0:
                        Project.Log(Level.Info, string.Format("Website [{0}] not created, because it already exists", m_websiteName));
                        break;
                    default:
                        Project.Log(Level.Info, string.Format("Website [{0}] created", m_websiteName));
                        break;
                }
            }
            catch (Exception ex)
            {
                logger.Log(this.Project, Level.Error, string.Format("Website [{0}] not created, because an exception occurred [{1}]", m_websiteName, ex.ToString()));
                throw new BuildException("Unable to create website", ex);
            }
        }

        /// <summary>
        /// Create an IIS website.
        /// </summary>
        /// <returns>Website id</returns>
        public int CreateWebsite()
        {
            if (string.IsNullOrEmpty(m_appPool)) { throw new Exception("Property [AppPool] can't be null or empty"); }
            if (string.IsNullOrEmpty(m_binding)) { throw new Exception("Parameter [Binding] can't be null or empty"); }
            if (string.IsNullOrEmpty(m_server)) { throw new Exception("Parameter [Server] can't be null or empty"); }
            if (string.IsNullOrEmpty(m_webFolder)) { throw new Exception("Parameter [WebFolder] can't be null or empty"); }
            if (string.IsNullOrEmpty(m_websiteName)) { throw new Exception("Parameter [WebsiteName] can't be null or empty"); }
            int websiteId = 1;

            using (DirectoryEntry w3svc = new DirectoryEntry(string.Format("IIS://{0}/w3svc", m_server)))
            {
                w3svc.RefreshCache();

                websiteId = this.GetWebSiteId(m_server, m_websiteName);

                if (websiteId < 0)
                {
                    //Create a website object array
                    object[] newsite = new object[] { m_websiteName, new object[] { m_binding }, m_webFolder };

                    //invoke IIsWebService.CreateNewSite
                    websiteId = (int)w3svc.Invoke("CreateNewSite", newsite);

                    // get newly created object
                    using (DirectoryEntry website = new DirectoryEntry(string.Format("IIS://{0}/w3svc/{1}", m_server, websiteId)))
                    {
                        website.RefreshCache();
                        // upgrade Scriptmap to 2.0.50272 (ASP.NET version)
                        for (int prop = 0; prop < website.Properties["ScriptMaps"].Count; prop++)
                        {
                            website.Properties["ScriptMaps"][prop] = website.Properties["ScriptMaps"][prop].ToString().Replace("v1.1.4322", "v2.0.50727");
                        }

                        // set application pool
                        website.Properties["AppPoolId"][0] = m_appPool;

                        // set Execute Permissions (0 - Scripts only, 512 - Script Only, 516 Script and Execute
                        website.Properties["AccessFlags"][0] = 512;

                        // set ReadAccess
                        website.Properties["AccessRead"][0] = true;

                        //// set Application Name (friendly name)
                        //// doesn't seem to work...
                        //w3svc.Properties["AppFriendlyName"][0] = siteDescription;

                        // Set Directory Security (Integrated Windows Authentication) 1 = AuthAnonymous, 2 = AuthBasic, 4 =AuthNTLM, 16 = AuthMD5(Digest), 64 = AuthPassport
                        website.Properties["AuthFlags"][0] = 5;

                        // save properties to IIS-metabase
                        website.CommitChanges();

                        // start website
                        website.Invoke("Start", null);
                    }
                }
                else
                {
                    websiteId = 0;
                }
            }

            return websiteId;
        }

        /// <summary>
        /// Get website id on websitename
        /// </summary>
        /// <param name="serverName">Name of the IIS server e.g. localhost</param>
        /// <param name="websiteName">Name of the website e.g. test</param>
        /// <returns>
        /// Less the 0, site does not exist
        /// Id of the existing site
        /// </returns>
        public int GetWebSiteId(string serverName, string websiteName)
        {
            if (string.IsNullOrEmpty(serverName)) { throw new Exception("Parameter [serverName] can't be null or empty"); }
            if (string.IsNullOrEmpty(websiteName)) { throw new Exception("Parameter [websiteName] can't be null or empty"); }
            int result = -1;

            using (DirectoryEntry w3svc = new DirectoryEntry(string.Format("IIS://{0}/w3svc", serverName)))
            {
                w3svc.RefreshCache();

                foreach (DirectoryEntry site in w3svc.Children)
                {
                    using (site)
                    {
                        site.RefreshCache();

                        if (site.Properties["ServerComment"] != null)
                        {
                            if (site.Properties["ServerComment"].Value != null)
                            {
                                if (site.Properties["ServerComment"].Value.ToString().Equals(websiteName, StringComparison.OrdinalIgnoreCase))
                                {
                                    result = int.Parse(site.Name);
                                }
                            }
                        }
                    }
                }
            }

            return result;
        }
    }
}

2 Comments

  1. Hi,

    The AppFriendlyName property must be set not on IisWebServer path, but under path + “/Root”!

    Eg: trying set AppFriendlyName under IIS://guiweb-01/w3svc/xyz will not work, but setting under IIS://guiweb-01/w3svc/xyz/Root, it works fine!

    I did that and It works!

    Guilherme

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.