/// <summary>
        /// Provision a list to the specified web using the list definition
        /// </summary>
        /// <param name="web">Client Context web</param>
        /// <param name="listDef">Hydrated list definition from JSON or Object</param>
        /// <param name="loggerVerbose">TODO: convert to static logger</param>
        /// <param name="loggerWarning">TODO: convert to static logger</param>
        /// <param name="loggerError">TODO: convert to static logger</param>
        /// <param name="SiteGroups">Collection of provisioned SharePoint group for field definitions</param>
        /// <param name="JsonFilePath">(OPTIONAL) file path to JSON folder</param>
        public static void CreateListFromDefinition(this Web web, SPListDefinition listDef, Action <string, string[]> loggerVerbose, Action <string, string[]> loggerWarning, Action <Exception, string, string[]> loggerError, List <SPGroupDefinitionModel> SiteGroups = null, string JsonFilePath = null)
        {
            var webContext = web.Context;

            var siteColumns           = new List <SPFieldDefinitionModel>();
            var afterProvisionChanges = false;

            // Content Type
            var listName        = listDef.ListName;
            var listDescription = listDef.ListDescription;


            // check to see if Picture library named Photos already exists
            ListCollection     allLists   = web.Lists;
            IEnumerable <List> foundLists = webContext.LoadQuery(allLists.Where(list => list.Title == listName)
                                                                 .Include(arl => arl.Title, arl => arl.Id, arl => arl.ContentTypes, ol => ol.RootFolder, ol => ol.EnableVersioning, ol => ol.EnableFolderCreation, ol => ol.ContentTypesEnabled));

            webContext.ExecuteQueryRetry();

            List listToProvision = foundLists.FirstOrDefault();

            if (listToProvision == null)
            {
                ListCreationInformation listToProvisionInfo = listDef.ToCreationObject();
                listToProvision = web.Lists.Add(listToProvisionInfo);
                webContext.Load(listToProvision, arl => arl.Title, arl => arl.Id, arl => arl.ContentTypes, ol => ol.RootFolder, ol => ol.EnableVersioning, ol => ol.EnableFolderCreation, ol => ol.ContentTypesEnabled);
                webContext.ExecuteQuery();
            }

            if (listDef.Versioning && !listToProvision.EnableVersioning)
            {
                afterProvisionChanges            = true;
                listToProvision.EnableVersioning = true;
                if (listDef.ListTemplate == ListTemplateType.DocumentLibrary)
                {
                    listToProvision.EnableMinorVersions = true;
                }
            }

            if (listDef.ContentTypeEnabled && !listToProvision.ContentTypesEnabled)
            {
                afterProvisionChanges = true;
                listToProvision.ContentTypesEnabled = true;
            }

            if (listDef.EnableFolderCreation && !listToProvision.EnableFolderCreation)
            {
                afterProvisionChanges = true;
                listToProvision.EnableFolderCreation = true;
            }

            if (afterProvisionChanges)
            {
                listToProvision.Update();
                webContext.Load(listToProvision);
                webContext.ExecuteQueryRetry();
            }

            webContext.Load(listToProvision, arl => arl.Title, arl => arl.Id, arl => arl.ContentTypes, ol => ol.RootFolder, ol => ol.EnableVersioning, ol => ol.EnableFolderCreation, ol => ol.ContentTypesEnabled);
            webContext.ExecuteQuery();

            if (listDef.ContentTypeEnabled && listDef.HasContentTypes)
            {
                foreach (var contentDef in listDef.ContentTypes)
                {
                    if (!listToProvision.ContentTypeExistsByName(contentDef.Name))
                    {
                        var ctypeInfo         = contentDef.ToCreationObject();
                        var accessContentType = listToProvision.ContentTypes.Add(ctypeInfo);
                        listToProvision.Update();
                        webContext.Load(accessContentType, tycp => tycp.Id, tycp => tycp.Name);
                        webContext.ExecuteQueryRetry();

                        if (contentDef.DefaultContentType)
                        {
                            listToProvision.SetDefaultContentTypeToList(accessContentType);
                        }
                    }
                }
            }


            // Site Columns
            foreach (var fieldDef in listDef.FieldDefinitions)
            {
                var column = listToProvision.CreateListColumn(fieldDef, loggerVerbose, loggerWarning, SiteGroups, JsonFilePath);
                if (column == null)
                {
                    loggerWarning("Failed to create column {0}.", new string[] { fieldDef.InternalName });
                }
                else
                {
                    siteColumns.Add(new SPFieldDefinitionModel()
                    {
                        InternalName = column.InternalName,
                        DisplayName  = column.Title,
                        FieldGuid    = column.Id
                    });
                }
            }

            if (listDef.ContentTypeEnabled && listDef.HasContentTypes)
            {
                foreach (var contentDef in listDef.ContentTypes)
                {
                    var contentTypeName    = contentDef.Name;
                    var accessContentTypes = listToProvision.ContentTypes;
                    IEnumerable <ContentType> allContentTypes = webContext.LoadQuery(accessContentTypes.Where(f => f.Name == contentTypeName).Include(tcyp => tcyp.Id, tcyp => tcyp.Name));
                    webContext.ExecuteQueryRetry();

                    if (allContentTypes != null)
                    {
                        var accessContentType = allContentTypes.FirstOrDefault();
                        foreach (var fieldInternalName in contentDef.FieldLinkRefs)
                        {
                            var column = siteColumns.FirstOrDefault(f => f.InternalName == fieldInternalName);
                            if (column != null)
                            {
                                var fieldLinks = accessContentType.FieldLinks;
                                webContext.Load(fieldLinks, cf => cf.Include(inc => inc.Id, inc => inc.Name));
                                webContext.ExecuteQueryRetry();

                                var convertedInternalName = column.DisplayNameMasked;
                                if (!fieldLinks.Any(a => a.Name == column.InternalName || a.Name == convertedInternalName))
                                {
                                    loggerVerbose("Content Type {0} Adding Field {1}", new string[] { contentTypeName, column.InternalName });
                                    var siteColumn = listToProvision.GetFieldById <Field>(column.FieldGuid);
                                    webContext.ExecuteQueryRetry();

                                    var flink = new FieldLinkCreationInformation();
                                    flink.Field = siteColumn;
                                    var flinkstub = accessContentType.FieldLinks.Add(flink);
                                    //if(fieldDef.Required) flinkstub.Required = fieldDef.Required;
                                    accessContentType.Update(false);
                                    webContext.ExecuteQueryRetry();
                                }
                            }
                            else
                            {
                                loggerWarning("Failed to create column {0}.", new string[] { fieldInternalName });
                            }
                        }
                    }
                }
            }


            // Views
            if (listDef.Views != null && listDef.Views.Count() > 0)
            {
                ViewCollection views = listToProvision.Views;
                webContext.Load(views, f => f.Include(inc => inc.Id, inc => inc.Hidden, inc => inc.Title, inc => inc.DefaultView));
                webContext.ExecuteQueryRetry();

                foreach (var viewDef in listDef.Views)
                {
                    try
                    {
                        if (views.Any(v => v.Title.Equals(viewDef.Title, StringComparison.CurrentCultureIgnoreCase)))
                        {
                            loggerVerbose("View {0} found in list {1}", new string[] { viewDef.Title, listName });
                            continue;
                        }

                        var view = listToProvision.CreateView(viewDef.InternalName, viewDef.ViewCamlType, viewDef.FieldRefName, viewDef.RowLimit, viewDef.DefaultView, viewDef.QueryXml, viewDef.PersonalView, viewDef.PagedView);
                        webContext.Load(view, v => v.Title, v => v.Id, v => v.ServerRelativeUrl);
                        webContext.ExecuteQueryRetry();

                        view.Title = viewDef.Title;
                        if (viewDef.HasJsLink)
                        {
                            view.JSLink = viewDef.JsLink;
                        }
                        view.Update();
                        webContext.ExecuteQueryRetry();
                    }
                    catch (Exception ex)
                    {
                        loggerError(ex, "Failed to create view {0} with XML:{1}", new string[] { viewDef.Title, viewDef.QueryXml });
                    }
                }
            }

            // List Data upload
            if (listDef.ListItems != null && listDef.ListItems.Count() > 0)
            {
                foreach (var listItem in listDef.ListItems)
                {
                    // Process the record into the notification email list
                    var itemCreateInfo = new ListItemCreationInformation();

                    var newSPListItem = listToProvision.AddItem(itemCreateInfo);
                    newSPListItem["Title"] = listItem.Title;
                    foreach (var listItemData in listItem.ColumnValues)
                    {
                        newSPListItem[listItemData.FieldName] = listItemData.FieldValue;
                    }

                    newSPListItem.Update();
                    webContext.ExecuteQueryRetry();
                }
            }
        }
        /// <summary>
        /// Provision Site Columns
        /// Provision Site Content Type
        /// Provision List
        /// Associate Content Type to List
        /// Provision List Views
        /// </summary>
        public void InstallComponentsToHostWeb(SiteProvisionerModel siteDefinition)
        {
            // obtain CSOM object for host web
            this.ClientContext.Load(this.ClientContext.Web, hw => hw.SiteGroups, hw => hw.Title, hw => hw.ContentTypes);
            this.ClientContext.ExecuteQuery();

            // creates groups
            siteGroups.AddRange(this.ClientContext.Web.GetOrCreateSiteGroups(siteDefinition.Groups));

            var fileJsonLocation = string.Format("{0}\\Content\\", this.SiteContent);

            foreach (var listDef in siteDefinition.Lists)
            {
                // Content Type
                var listName        = listDef.ListName;
                var listDescription = listDef.ListDescription;

                // Site Columns
                FieldCollection fields = this.ClientContext.Web.Fields;
                this.ClientContext.Load(fields, f => f.Include(inc => inc.InternalName, inc => inc.JSLink, inc => inc.Title, inc => inc.Id));
                this.ClientContext.ExecuteQuery();

                // Create List Columns
                foreach (var fieldDef in listDef.FieldDefinitions)
                {
                    var column = this.ClientContext.Web.CreateColumn(fieldDef, LogVerbose, LogError, siteGroups, fileJsonLocation);
                    if (column == null)
                    {
                        LogWarning("Failed to create column {0}.", fieldDef.InternalName);
                    }
                    else
                    {
                        siteColumns.Add(new SPFieldDefinitionModel()
                        {
                            InternalName = column.InternalName,
                            DisplayName  = column.Title,
                            FieldGuid    = column.Id
                        });
                    }
                }

                foreach (var contentDef in listDef.ContentTypes)
                {
                    var contentTypeName = contentDef.Name;
                    var contentTypeId   = contentDef.ContentTypeId;

                    if (!this.ClientContext.Web.ContentTypeExistsById(contentTypeId))
                    {
                        this.ClientContext.Web.CreateContentType(contentTypeName, contentTypeId, contentDef.ContentTypeGroup);
                    }

                    foreach (var fieldDef in contentDef.FieldLinkRefs)
                    {
                        var siteColumn            = listDef.FieldDefinitions.FirstOrDefault(f => f.InternalName == fieldDef);
                        var convertedInternalName = siteColumn.DisplayNameMasked;
                        if (!this.ClientContext.Web.FieldExistsByNameInContentType(contentTypeName, fieldDef) &&
                            !this.ClientContext.Web.FieldExistsByNameInContentType(contentTypeName, convertedInternalName))
                        {
                            var column = this.siteColumns.FirstOrDefault(f => f.InternalName == fieldDef);
                            this.ClientContext.Web.AddFieldToContentTypeByName(contentTypeName, column.FieldGuid, siteColumn.Required);
                        }
                    }

                    // check to see if Picture library named Photos already exists
                    ListCollection     allLists   = this.ClientContext.Web.Lists;
                    IEnumerable <List> foundLists = this.ClientContext.LoadQuery(allLists.Where(list => list.Title == listName));
                    this.ClientContext.ExecuteQuery();

                    List accessRequest = foundLists.FirstOrDefault();
                    if (accessRequest == null)
                    {
                        // create Picture library named Photos if it does not already exist
                        ListCreationInformation accessRequestInfo = new ListCreationInformation();
                        accessRequestInfo.Title             = listName;
                        accessRequestInfo.Description       = listDescription;
                        accessRequestInfo.QuickLaunchOption = listDef.QuickLaunch;
                        accessRequestInfo.TemplateType      = (int)listDef.ListTemplate;
                        accessRequestInfo.Url = listName;
                        accessRequest         = this.ClientContext.Web.Lists.Add(accessRequestInfo);
                        this.ClientContext.ExecuteQuery();

                        if (listDef.ContentTypeEnabled)
                        {
                            List list = this.ClientContext.Web.GetListByTitle(listName);
                            list.ContentTypesEnabled = true;
                            list.Update();
                            this.ClientContext.Web.Context.ExecuteQuery();
                        }
                    }

                    if (listDef.ContentTypeEnabled)
                    {
                        if (!this.ClientContext.Web.ContentTypeExistsByName(listName, contentTypeName))
                        {
                            this.ClientContext.Web.AddContentTypeToListByName(listName, contentTypeName, true);
                        }

                        // Set the content type as default content type to the TestLib list
                        //this.ClientContext.Web.SetDefaultContentTypeToList(listName, contentTypeId);
                    }

                    // Views
                    ViewCollection views = accessRequest.Views;
                    this.ClientContext.Load(views, f => f.Include(inc => inc.Id, inc => inc.Hidden, inc => inc.Title, inc => inc.DefaultView));
                    this.ClientContext.ExecuteQuery();

                    foreach (var viewDef in listDef.Views)
                    {
                        try
                        {
                            if (views.Any(v => v.Title == viewDef.Title))
                            {
                                LogVerbose("View {0} found in list {1}", viewDef.Title, listName);
                                continue;
                            }

                            var view = accessRequest.CreateView(viewDef.InternalName, viewDef.ViewCamlType, viewDef.FieldRefName, viewDef.RowLimit, viewDef.DefaultView, viewDef.QueryXml);
                            this.ClientContext.Load(view, v => v.Title, v => v.Id, v => v.ServerRelativeUrl);
                            this.ClientContext.ExecuteQuery();

                            view.Title = viewDef.Title;
                            view.Update();
                            this.ClientContext.ExecuteQuery();
                        }
                        catch (Exception ex)
                        {
                            LogError(ex, "Failed to create view {0} with XML:{1}", viewDef.Title, viewDef.QueryXml);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Process the request
        /// </summary>
        public override void ExecuteCmdlet()
        {
            base.ExecuteCmdlet();

            // Initialize logging instance with Powershell logger
            ITraceLogger logger = new DefaultUsageLogger(LogVerbose, LogWarning, LogError);

            // SharePoint URI for XML parsing
            XNamespace ns = "http://schemas.microsoft.com/sharepoint/";

            // Definition file to operate on
            SiteProvisionerModel siteDefinition = null;

            try
            {
                // Retreive JSON Provisioner file and deserialize it
                var filePath     = new System.IO.FileInfo(this.ProvisionerFilePath);
                var filePathJSON = System.IO.File.ReadAllText(filePath.FullName);
                siteDefinition = JsonConvert.DeserializeObject <SiteProvisionerModel>(filePathJSON);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Failed to parse {0} Exception {1}", ProvisionerFilePath, ex.Message);
                return;
            }


            if (ValidateJson)
            {
                logger.LogInformation("The file {0} is valid.", ProvisionerFilePath);
                return;
            }

            var provisionerChoices = siteDefinition.FieldChoices;

            // Load the Context
            var contextWeb = this.ClientContext.Web;

            this.ClientContext.Load(contextWeb,
                                    ctxw => ctxw.ServerRelativeUrl,
                                    ctxw => ctxw.Id,
                                    ctxw => ctxw.Fields.Include(inc => inc.InternalName, inc => inc.JSLink, inc => inc.Title, inc => inc.Id));

            // All Site Columns
            var siteFields = this.ClientContext.LoadQuery(ClientContext.Web.AvailableFields
                                                          .Include(inc => inc.InternalName, inc => inc.JSLink, inc => inc.Title, inc => inc.Id));

            // pull Site Groups
            var groupQuery = this.ClientContext.LoadQuery(contextWeb.SiteGroups
                                                          .Include(group => group.Id,
                                                                   group => group.Title,
                                                                   group => group.Description,
                                                                   group => group.AllowRequestToJoinLeave,
                                                                   group => group.AllowMembersEditMembership,
                                                                   group => group.AutoAcceptRequestToJoinLeave,
                                                                   group => group.OnlyAllowMembersViewMembership,
                                                                   group => group.RequestToJoinLeaveEmailSetting));

            var contentTypes = this.ClientContext.LoadQuery(contextWeb.ContentTypes
                                                            .Include(
                                                                ict => ict.Id,
                                                                ict => ict.Group,
                                                                ict => ict.Description,
                                                                ict => ict.Name,
                                                                ict => ict.Hidden,
                                                                ict => ict.JSLink,
                                                                ict => ict.FieldLinks,
                                                                ict => ict.Fields));


            var collists = contextWeb.Lists;
            var lists    = this.ClientContext.LoadQuery(collists
                                                        .Include(
                                                            linc => linc.Title,
                                                            linc => linc.Id,
                                                            linc => linc.Description,
                                                            linc => linc.Hidden,
                                                            linc => linc.OnQuickLaunch,
                                                            linc => linc.BaseTemplate,
                                                            linc => linc.ContentTypesEnabled,
                                                            linc => linc.AllowContentTypes,
                                                            linc => linc.EnableFolderCreation,
                                                            linc => linc.IsApplicationList,
                                                            linc => linc.IsCatalog,
                                                            linc => linc.IsSiteAssetsLibrary,
                                                            linc => linc.IsPrivate,
                                                            linc => linc.IsSystemList,
                                                            linc => linc.Views,
                                                            linc => linc.Fields
                                                            .Include(
                                                                lft => lft.Id,
                                                                lft => lft.AutoIndexed,
                                                                lft => lft.CanBeDeleted,
                                                                lft => lft.DefaultFormula,
                                                                lft => lft.DefaultValue,
                                                                lft => lft.Group,
                                                                lft => lft.Description,
                                                                lft => lft.EnforceUniqueValues,
                                                                lft => lft.FieldTypeKind,
                                                                lft => lft.Filterable,
                                                                lft => lft.Hidden,
                                                                lft => lft.Indexed,
                                                                lft => lft.InternalName,
                                                                lft => lft.JSLink,
                                                                lft => lft.NoCrawl,
                                                                lft => lft.ReadOnlyField,
                                                                lft => lft.Required,
                                                                lft => lft.SchemaXml,
                                                                lft => lft.Scope,
                                                                lft => lft.Title
                                                                ),
                                                            linc => linc.ContentTypes
                                                            .Include(
                                                                ict => ict.Id,
                                                                ict => ict.Group,
                                                                ict => ict.Description,
                                                                ict => ict.Name,
                                                                ict => ict.Hidden,
                                                                ict => ict.JSLink,
                                                                ict => ict.FieldLinks,
                                                                ict => ict.Fields)).Where(w => !w.IsSystemList && !w.IsSiteAssetsLibrary));

            this.ClientContext.ExecuteQueryRetry();



            // creates groups
            contextWeb.Context.Load(contextWeb, hw => hw.CurrentUser);
            contextWeb.Context.ExecuteQueryRetry();


            if (ProvisionGroups)
            {
                if (siteDefinition.Groups != null && siteDefinition.Groups.Any())
                {
                    logger.LogInformation("Group collection will be provisioned for {0} groups", siteDefinition.Groups.Count());
                    foreach (var groupDef in siteDefinition.Groups)
                    {
                        if (groupQuery.Any(g => g.Title.Equals(groupDef.Title, StringComparison.CurrentCultureIgnoreCase)))
                        {
                            var group = groupQuery.FirstOrDefault(g => g.Title.Equals(groupDef.Title, StringComparison.CurrentCultureIgnoreCase));
                            SiteGroups.Add(new SPGroupDefinitionModel()
                            {
                                Id = group.Id, Title = group.Title
                            });
                        }
                        else
                        {
                            var newgroup = contextWeb.GetOrCreateSiteGroups(groupDef);
                            SiteGroups.Add(new SPGroupDefinitionModel()
                            {
                                Id = newgroup.Id, Title = newgroup.Title
                            });
                        }
                    }
                }
            }
            else
            {
                // we aren't going to examine the JSON to provision groups, pull from current SharePoint instance
                SiteGroups.AddRange(groupQuery.Select(gq => new SPGroupDefinitionModel()
                {
                    Id = gq.Id, Title = gq.Title
                }));
            }

            // provision columns
            // Site Columns
            if (siteDefinition.FieldDefinitions != null && siteDefinition.FieldDefinitions.Any())
            {
                logger.LogInformation("Field definitions will be provisioned for {0} fields", siteDefinition.FieldDefinitions.Count());
                foreach (var fieldDef in siteDefinition.FieldDefinitions)
                {
                    var column = contextWeb.CreateColumn(fieldDef, logger, SiteGroups, siteDefinition.FieldChoices);
                    if (column == null)
                    {
                        logger.LogWarning("Failed to create column {0}.", fieldDef.InternalName);
                    }
                    else
                    {
                        SiteColumns.Add(new SPFieldDefinitionModel()
                        {
                            InternalName = column.InternalName,
                            Title        = column.Title,
                            FieldGuid    = column.Id
                        });
                    }
                }
            }


            // provision content types
            if (siteDefinition.ContentTypes != null && siteDefinition.ContentTypes.Any())
            {
                logger.LogInformation("Content types will be provisioned for {0} ctypes", siteDefinition.ContentTypes.Count());
                foreach (var contentDef in siteDefinition.ContentTypes)
                {
                    var contentTypeName = contentDef.Name;
                    var contentTypeId   = contentDef.ContentTypeId;

                    if (!contextWeb.ContentTypeExistsByName(contentTypeName) &&
                        !contextWeb.ContentTypeExistsById(contentTypeId))
                    {
                        logger.LogInformation("Provisioning content type {0}", contentTypeName);
                        contextWeb.CreateContentType(contentTypeName, contentTypeId, (string.IsNullOrEmpty(contentDef.ContentTypeGroup) ? "CustomColumn" : contentDef.ContentTypeGroup));
                    }

                    var provisionedContentType = contextWeb.GetContentTypeByName(contentTypeName, true);
                    if (provisionedContentType != null)
                    {
                        logger.LogInformation("Found content type {0} and is read only {1}", contentTypeName, provisionedContentType.ReadOnly);
                        if (!provisionedContentType.ReadOnly)
                        {
                            foreach (var fieldDef in contentDef.FieldLinks)
                            {
                                // Check if FieldLink exists in the Content Type
                                if (!contextWeb.FieldExistsByNameInContentType(contentTypeName, fieldDef.Name))
                                {
                                    // Check if FieldLInk column is in the collection of FieldDefinition
                                    var siteColumn = siteDefinition.FieldDefinitions.FirstOrDefault(f => f.InternalName == fieldDef.Name);
                                    if (siteColumn != null && !contextWeb.FieldExistsByNameInContentType(contentTypeName, siteColumn.DisplayNameMasked))
                                    {
                                        var column = this.SiteColumns.FirstOrDefault(f => f.InternalName == fieldDef.Name);
                                        if (column == null)
                                        {
                                            logger.LogWarning("Column {0} was not added to the collection", fieldDef.Name);
                                        }
                                        else
                                        {
                                            contextWeb.AddFieldToContentTypeByName(contentTypeName, column.FieldGuid, siteColumn.Required);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }


            // provision lists
            var listtoprocess = siteDefinition.Lists.OrderBy(w => w.ProvisionOrder).ToList();

            listtoprocess.ForEach(listDef =>
            {
                // Content Type
                var listName        = listDef.ListName;
                var listDescription = listDef.ListDescription;


                // provision the list definition
                var siteList = contextWeb.CreateListFromDefinition(listDef, provisionerChoices);

                if (listDef.ContentTypeEnabled && listDef.HasContentTypes)
                {
                    if (listDef.ContentTypes != null && listDef.ContentTypes.Any())
                    {
                        logger.LogInformation("List {0} => Content types will be provisioned for {1} ctypes", listDef.ListName, listDef.ContentTypes.Count());
                        foreach (var contentDef in listDef.ContentTypes)
                        {
                            var contentTypeName           = contentDef.Name;
                            ContentType accessContentType = null;

                            if (!contextWeb.ContentTypeExistsByName(listName, contentTypeName))
                            {
                                if (siteDefinition.ContentTypes != null && siteDefinition.ContentTypes.Any(ct => ct.Name == contentTypeName))
                                {
                                    contextWeb.AddContentTypeToListByName(listName, contentTypeName, true);
                                    accessContentType = siteList.GetContentTypeByName(contentTypeName);
                                }
                                else
                                {
                                    var ctypeInfo     = contentDef.ToCreationObject();
                                    accessContentType = siteList.ContentTypes.Add(ctypeInfo);
                                    siteList.Update();
                                    siteList.Context.Load(accessContentType, tycp => tycp.Id, tycp => tycp.Name);
                                    siteList.Context.ExecuteQueryRetry();
                                }

                                if (contentDef.DefaultContentType)
                                {
                                    siteList.SetDefaultContentType(accessContentType.Id);
                                }
                            }
                        }
                    }
                }

                // Existing columns
                var internalNamesForList     = listDef.FieldDefinitions.Select(s => s.InternalName).ToArray();
                var internalNamesFoundInList = new List <string>();
                try
                {
                    var existingListColumns = siteList.GetFields(internalNamesForList);
                    foreach (var column in existingListColumns)
                    {
                        ListColumns.Add(new SPFieldDefinitionModel()
                        {
                            InternalName = column.InternalName,
                            Title        = column.Title,
                            FieldGuid    = column.Id
                        });
                        internalNamesFoundInList.Add(column.InternalName);
                    }
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "List {0} => failed to query columns by internal names {1}", listDef.ListName, ex.Message);
                }

                // List Columns
                var nonExistingListColumns = listDef.FieldDefinitions.Where(fd => !internalNamesFoundInList.Any(inf => fd.InternalName.Equals(inf, StringComparison.InvariantCultureIgnoreCase)));
                foreach (var fieldDef in nonExistingListColumns)
                {
                    if (fieldDef.FromBaseType == true && fieldDef.SourceID.IndexOf(ns.NamespaceName, StringComparison.CurrentCultureIgnoreCase) > -1)
                    {
                        // OOTB Column
                        var hostsitecolumn = siteFields.FirstOrDefault(fd => fd.InternalName == fieldDef.InternalName);
                        if (hostsitecolumn != null && !siteList.FieldExistsByName(hostsitecolumn.InternalName))
                        {
                            var column = siteList.Fields.Add(hostsitecolumn);
                            siteList.Update();
                            siteList.Context.Load(column, cctx => cctx.Id, cctx => cctx.InternalName);
                            siteList.Context.ExecuteQueryRetry();
                        }

                        var sourceListColumns = siteList.GetFields(fieldDef.InternalName);
                        foreach (var column in sourceListColumns)
                        {
                            ListColumns.Add(new SPFieldDefinitionModel()
                            {
                                InternalName = column.InternalName,
                                Title        = column.Title,
                                FieldGuid    = column.Id
                            });
                        }
                    }
                    else if (fieldDef.FieldTypeKind == FieldType.Invalid &&
                             fieldDef.FieldTypeKindText.IndexOf("TaxonomyFieldType", StringComparison.InvariantCultureIgnoreCase) > -1)
                    {
                        // Taxonomy Column
                        var hostsitecolumn = siteFields.FirstOrDefault(fd => fd.InternalName == fieldDef.InternalName);
                        if (hostsitecolumn != null && !siteList.FieldExistsByName(hostsitecolumn.InternalName))
                        {
                            var column = siteList.Fields.Add(hostsitecolumn);
                            siteList.Update();
                            siteList.Context.Load(column, cctx => cctx.Id, cctx => cctx.InternalName);
                            siteList.Context.ExecuteQueryRetry();
                        }

                        var sourceListColumns = siteList.GetFields(fieldDef.InternalName);
                        foreach (var column in sourceListColumns)
                        {
                            ListColumns.Add(new SPFieldDefinitionModel()
                            {
                                InternalName = column.InternalName,
                                Title        = column.Title,
                                FieldGuid    = column.Id
                            });
                        }
                    }
                    else
                    {
                        var column = siteList.CreateListColumn(fieldDef, logger, SiteGroups, provisionerChoices);
                        if (column == null)
                        {
                            logger.LogWarning("Failed to create column {0}.", fieldDef.InternalName);
                        }
                        else
                        {
                            ListColumns.Add(new SPFieldDefinitionModel()
                            {
                                InternalName = column.InternalName,
                                Title        = column.Title,
                                FieldGuid    = column.Id
                            });
                        }
                    }
                }

                // Where content types are enabled
                // Add the provisioned site columns or list columns to the content type
                if (listDef.ContentTypeEnabled && listDef.HasContentTypes)
                {
                    foreach (var contentDef in listDef.ContentTypes)
                    {
                        var contentTypeName    = contentDef.Name;
                        var accessContentTypes = siteList.ContentTypes;
                        IEnumerable <ContentType> allContentTypes = contextWeb.Context.LoadQuery(accessContentTypes.Where(f => f.Name == contentTypeName).Include(tcyp => tcyp.Id, tcyp => tcyp.Name));
                        contextWeb.Context.ExecuteQueryRetry();

                        if (allContentTypes != null)
                        {
                            var accessContentType = allContentTypes.FirstOrDefault();
                            foreach (var fieldInternalName in contentDef.FieldLinks)
                            {
                                var column = ListColumns.FirstOrDefault(f => f.InternalName == fieldInternalName.Name);
                                if (column == null)
                                {
                                    logger.LogWarning("List {0} => Failed to associate field link {1}.", listDef.ListName, fieldInternalName.Name);
                                    continue;
                                }

                                var fieldLinks = accessContentType.FieldLinks;
                                contextWeb.Context.Load(fieldLinks, cf => cf.Include(inc => inc.Id, inc => inc.Name));
                                contextWeb.Context.ExecuteQueryRetry();

                                var convertedInternalName = column.DisplayNameMasked;
                                if (!fieldLinks.Any(a => a.Name == column.InternalName || a.Name == convertedInternalName))
                                {
                                    logger.LogInformation("List {0} => Content Type {1} Adding Field {2}", listDef.ListName, contentTypeName, column.InternalName);
                                    var siteColumn = siteList.GetFieldById <Field>(column.FieldGuid);
                                    contextWeb.Context.ExecuteQueryRetry();

                                    var flink = new FieldLinkCreationInformation
                                    {
                                        Field = siteColumn
                                    };
                                    var flinkstub = accessContentType.FieldLinks.Add(flink);
                                    //if(fieldDef.Required) flinkstub.Required = fieldDef.Required;
                                    accessContentType.Update(false);
                                    contextWeb.Context.ExecuteQueryRetry();
                                }
                            }
                        }
                    }
                }


                // Views
                if (listDef.Views != null && listDef.Views.Any())
                {
                    ViewCollection views = siteList.Views;
                    contextWeb.Context.Load(views, f => f.Include(inc => inc.Id, inc => inc.Hidden, inc => inc.Title, inc => inc.DefaultView));
                    contextWeb.Context.ExecuteQueryRetry();

                    foreach (var modelView in listDef.Views)
                    {
                        try
                        {
                            var updatecaml = false;
                            View view      = null;
                            if (views.Any(v => v.Title.Equals(modelView.Title, StringComparison.CurrentCultureIgnoreCase)))
                            {
                                logger.LogInformation("List {0} => View {1} found in list", listName, modelView.Title);
                                view       = views.FirstOrDefault(v => v.Title.Equals(modelView.Title, StringComparison.CurrentCultureIgnoreCase));
                                updatecaml = true;
                            }
                            else
                            {
                                logger.LogInformation("List {0} => Creating View {0} in list", listName, modelView.Title);
                                view = siteList.CreateView(modelView.CalculatedInternalName, modelView.ViewCamlType, modelView.FieldRefName.ToArray(), modelView.RowLimit, modelView.DefaultView, modelView.ViewQuery, modelView.PersonalView, modelView.Paged);
                            }

                            // grab the view properties from the object
                            view.EnsureProperties(
                                mview => mview.Title,
                                mview => mview.Scope,
                                mview => mview.AggregationsStatus,
                                mview => mview.Aggregations,
                                mview => mview.DefaultView,
                                mview => mview.Hidden,
                                mview => mview.Toolbar,
                                mview => mview.JSLink,
                                mview => mview.ViewFields,
                                vctx => vctx.ViewQuery
                                );


                            if (modelView.FieldRefName != null && modelView.FieldRefName.Any())
                            {
                                var currentFields = view.ViewFields;
                                currentFields.RemoveAll();
                                modelView.FieldRefName.ToList().ForEach(vField =>
                                {
                                    currentFields.Add(vField.Trim());
                                });
                            }

                            if (!string.IsNullOrEmpty(modelView.Aggregations))
                            {
                                view.Aggregations       = modelView.Aggregations;
                                view.AggregationsStatus = modelView.AggregationsStatus;
                            }

                            if (modelView.Hidden.HasValue && modelView.Hidden == true)
                            {
                                view.Hidden = modelView.Hidden.Value;
                            }

                            if (modelView.ToolBarType.HasValue)
                            {
                                view.Toolbar = string.Format("<Toolbar Type=\"{0}\"/>", modelView.ToolBarType.ToString());
                            }

                            if (updatecaml)
                            {
                                view.DefaultView = modelView.DefaultView;
                                view.RowLimit    = modelView.RowLimit;
                                view.ViewQuery   = modelView.ViewQuery;
                            }

                            if (modelView.HasJsLink && modelView.JsLink.IndexOf("clienttemplates.js") == -1)
                            {
                                view.JSLink = modelView.JsLink;
                            }

                            view.Scope = modelView.Scope;
                            view.Title = modelView.Title;
                            view.Update();
                            contextWeb.Context.Load(view, v => v.Title, v => v.Id, v => v.ServerRelativeUrl);
                            contextWeb.Context.ExecuteQueryRetry();
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "List {0} => Failed to create view {1} with XML:{2}", listDef.ListName, modelView.Title, modelView.ViewQuery);
                        }
                    }
                }
            });
        }