/// <summary>
 /// Determines if the column is a lookup
 /// </summary>
 /// <param name="List"></param>
 /// <param name="ColumnName"></param>
 /// <param name="LookupListName"></param>
 /// <returns></returns>
 static bool IsLookup(SPListDefinition List, string ColumnName, out SPFieldDefinitionModel LookupField)
 {
     LookupField = null;
     foreach (var spc in List.FieldDefinitions
              .Where(sfield => sfield.InternalName.Equals(ColumnName, StringComparison.CurrentCultureIgnoreCase) && sfield.FieldTypeKind == FieldType.Lookup))
     {
         LookupField = spc;
         return(true);
     }
     return(false);
 }
Example #2
0
        /// <summary>
        /// Provisions a site column based on the field definition specified
        /// </summary>
        /// <param name="hostWeb">The instantiated site/web to which the column will be retrieved and/or provisioned</param>
        /// <param name="fieldDefinition">The definition for the field</param>
        /// <param name="loggerVerbose">Provides a method for verbose logging</param>
        /// <param name="loggerError">Provides a method for exception logging</param>
        /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param>
        /// <param name="provisionerChoices">(OPTIONAL) deserialized choices from JSON</param>
        /// <returns></returns>
        public static Field CreateColumn(this Web hostWeb, SPFieldDefinitionModel fieldDefinition, ITraceLogger logger, List <SPGroupDefinitionModel> SiteGroups, List <SiteProvisionerFieldChoiceModel> provisionerChoices = null)
        {
            if (fieldDefinition == null)
            {
                throw new ArgumentNullException("fieldDef", "Field definition is required.");
            }

            if (string.IsNullOrEmpty(fieldDefinition.InternalName))
            {
                throw new ArgumentNullException("InternalName");
            }

            if (fieldDefinition.LoadFromJSON && (provisionerChoices == null || !provisionerChoices.Any(pc => pc.FieldInternalName == fieldDefinition.InternalName)))
            {
                throw new ArgumentNullException("provisionerChoices", string.Format("You must specify a collection of field choices for the field {0}", fieldDefinition.Title));
            }

            var fields = hostWeb.Context.LoadQuery(hostWeb.Fields.Include(f => f.Id, f => f.InternalName, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required));

            hostWeb.Context.ExecuteQueryRetry();


            var returnField = fields.FirstOrDefault(f => f.Id == fieldDefinition.FieldGuid || f.InternalName == fieldDefinition.InternalName || f.Title == fieldDefinition.InternalName);

            if (returnField == null)
            {
                var finfoXml = hostWeb.CreateFieldDefinition(fieldDefinition, SiteGroups, provisionerChoices);
                logger.LogInformation("Provision Site field {0} with XML:{1}", fieldDefinition.InternalName, finfoXml);
                try
                {
                    var createdField = hostWeb.CreateField(finfoXml, executeQuery: false);
                    hostWeb.Context.ExecuteQueryRetry();
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "EXCEPTION: field {0} with message {1}", fieldDefinition.InternalName, ex.Message);
                }
                finally
                {
                    returnField = hostWeb.Fields.GetByInternalNameOrTitle(fieldDefinition.InternalName);
                    hostWeb.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required);
                    hostWeb.Context.ExecuteQuery();
                }
            }

            return(returnField);
        }
Example #3
0
        /// <summary>
        /// Provisions a column based on the field defintion to the host list
        /// </summary>
        /// <param name="hostList">The instantiated list/library to which the field will be added</param>
        /// <param name="fieldDef">The definition for the field</param>
        /// <param name="loggerVerbose">Provides a method for verbose logging</param>
        /// <param name="loggerError">Provides a method for exception logging</param>
        /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param>
        /// <param name="JsonFilePath">(OPTIONAL) file path except if loading choices from JSON</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">For field definitions that do not contain all required data</exception>
        public static Field CreateListColumn(this List hostList, SPFieldDefinitionModel fieldDef, Action <string, string[]> loggerVerbose, Action <string, string[]> loggerError, List <SPGroupDefinitionModel> SiteGroups, string JsonFilePath = null)
        {
            if (fieldDef == null)
            {
                throw new ArgumentNullException("fieldDef", "Field definition is required.");
            }

            if (!hostList.IsPropertyAvailable("Context"))
            {
            }

            var fields = hostList.Fields;

            hostList.Context.Load(fields, fc => fc.Include(f => f.Id, f => f.InternalName, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required));
            hostList.Context.ExecuteQueryRetry();

            var returnField = fields.FirstOrDefault(f => f.Id == fieldDef.FieldGuid || f.InternalName == fieldDef.InternalName);

            if (returnField == null)
            {
                try
                {
                    var baseFieldXml = hostList.CreateFieldDefinition(fieldDef, SiteGroups, JsonFilePath);
                    loggerVerbose("Provision field {0} with XML:{1}", new string[] { fieldDef.InternalName, baseFieldXml });

                    // Should throw an exception if the field ID or Name exist in the list
                    var baseField = hostList.CreateField(baseFieldXml, fieldDef.AddToDefaultView, executeQuery: false);
                    hostList.Context.ExecuteQueryRetry();
                }
                catch (Exception ex)
                {
                    var msg = ex.Message;
                    loggerError("EXCEPTION: field {0} with message {1}", new string[] { fieldDef.InternalName, msg });
                }
                finally
                {
                    returnField = hostList.Fields.GetByInternalNameOrTitle(fieldDef.InternalName);
                    hostList.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required);
                    hostList.Context.ExecuteQueryRetry();
                }
            }

            return(returnField);
        }
        /// <summary>
        /// Provisions a column based on the field defintion to the host list
        /// </summary>
        /// <param name="hostList">The instantiated list/library to which the field will be added</param>
        /// <param name="fieldDefinition">The definition for the field</param>
        /// <param name="loggerVerbose">Provides a method for verbose logging</param>
        /// <param name="loggerError">Provides a method for exception logging</param>
        /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param>
        /// <param name="provisionerChoices">(OPTIONAL) deserialized choices from JSON</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">For field definitions that do not contain all required data</exception>
        public static Field CreateListColumn(this List hostList, SPFieldDefinitionModel fieldDefinition, ITraceLogger logger, List <SPGroupDefinitionModel> SiteGroups, List <SiteProvisionerFieldChoiceModel> provisionerChoices = null)
        {
            if (fieldDefinition == null)
            {
                throw new ArgumentNullException("fieldDef", "Field definition is required.");
            }

            if (fieldDefinition.LoadFromJSON && (provisionerChoices == null || !provisionerChoices.Any(pc => pc.FieldInternalName == fieldDefinition.InternalName)))
            {
                throw new ArgumentNullException("provisionerChoices", string.Format("You must specify a collection of field choices for the field {0}", fieldDefinition.Title));
            }

            // load fields into memory
            hostList.Context.Load(hostList.Fields, fc => fc.Include(f => f.Id, f => f.InternalName, fctx => fctx.Title, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required));
            hostList.Context.ExecuteQueryRetry();

            var returnField = hostList.Fields.FirstOrDefault(f => f.Id == fieldDefinition.FieldGuid || f.InternalName == fieldDefinition.InternalName);

            if (returnField == null)
            {
                try
                {
                    var baseFieldXml = hostList.CreateFieldDefinition(fieldDefinition, SiteGroups, provisionerChoices);
                    logger.LogInformation("Provision List {0} field {1} with XML:{2}", hostList.Title, fieldDefinition.InternalName, baseFieldXml);

                    // Should throw an exception if the field ID or Name exist in the list
                    var baseField = hostList.CreateField(baseFieldXml, fieldDefinition.AddToDefaultView, executeQuery: false);
                    hostList.Context.ExecuteQueryRetry();
                }
                catch (Exception ex)
                {
                    var msg = ex.Message;
                    logger.LogError(ex, "EXCEPTION: field {0} with message {1}", fieldDefinition.InternalName, msg);
                }
                finally
                {
                    returnField = hostList.Fields.GetByInternalNameOrTitle(fieldDefinition.InternalName);
                    hostList.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required);
                    hostList.Context.ExecuteQueryRetry();
                }
            }

            return(returnField);
        }
        /// <summary>
        /// Provisions a site column based on the field definition specified
        /// </summary>
        /// <param name="hostWeb">The instantiated site/web to which the column will be retrieved and/or provisioned</param>
        /// <param name="fieldDef">The definition for the field</param>
        /// <param name="loggerVerbose">Provides a method for verbose logging</param>
        /// <param name="loggerError">Provides a method for exception logging</param>
        /// <param name="SiteGroups">(OPTIONAL) collection of group, required if this is a PeoplePicker field</param>
        /// <param name="JsonFilePath">(OPTIONAL) file path except if loading choices from JSON</param>
        /// <returns></returns>
        public static Field CreateColumn(this Web hostWeb, SPFieldDefinitionModel fieldDef, Action <string, string[]> loggerVerbose, Action <Exception, string, string[]> loggerError, List <SPGroupDefinitionModel> SiteGroups, string JsonFilePath = null)
        {
            if (!hostWeb.IsPropertyAvailable("Context"))
            {
            }

            var fields = hostWeb.Fields;

            hostWeb.Context.Load(fields, fc => fc.Include(f => f.Id, f => f.InternalName, f => f.Title, f => f.JSLink, f => f.Indexed, f => f.CanBeDeleted, f => f.Required));
            hostWeb.Context.ExecuteQueryRetry();


            var returnField = fields.FirstOrDefault(f => f.Id == fieldDef.FieldGuid || f.InternalName == fieldDef.InternalName);

            if (returnField == null)
            {
                var finfoXml = hostWeb.CreateFieldDefinition(fieldDef, SiteGroups, JsonFilePath);
                loggerVerbose("Provision field {0} with XML:{1}", new string[] { fieldDef.InternalName, finfoXml });
                try
                {
                    var createdField = hostWeb.CreateField(finfoXml, executeQuery: false);
                    hostWeb.Context.ExecuteQueryRetry();
                }
                catch (Exception ex)
                {
                    loggerError(ex, "EXCEPTION: field {0} with message {1}", new string[] { fieldDef.InternalName, ex.Message });
                }
                finally
                {
                    returnField = hostWeb.Fields.GetByInternalNameOrTitle(fieldDef.InternalName);
                    hostWeb.Context.Load(returnField, fd => fd.Id, fd => fd.Title, fd => fd.Indexed, fd => fd.InternalName, fd => fd.CanBeDeleted, fd => fd.Required);
                    hostWeb.Context.ExecuteQuery();
                }
            }

            return(returnField);
        }
        /// <summary>
        /// Builds a Field Creation Info object from the Definition model and returns its resulting XML
        /// </summary>
        /// <param name="host">The instantiated web/list/library to which the field will be added</param>
        /// <param name="fieldDefinition">The definition pulled from a SP Site or user construction</param>
        /// <param name="siteGroups">The collection of site groups that a user/group field make filter</param>
        /// <param name="JsonFilePath">The file path to a JSON file containing Choice lookups</param>
        /// <returns></returns>
        public static string CreateFieldDefinition(this SecurableObject host, SPFieldDefinitionModel fieldDefinition, List <SPGroupDefinitionModel> siteGroups, string JsonFilePath = null)
        {
            var idguid           = fieldDefinition.FieldGuid;
            var choiceXml        = string.Empty;
            var defaultChoiceXml = string.Empty;
            var attributes       = new List <KeyValuePair <string, string> >();

            if (string.IsNullOrEmpty(fieldDefinition.InternalName))
            {
                throw new ArgumentNullException("InternalName");
            }

            if (string.IsNullOrEmpty(fieldDefinition.DisplayName))
            {
                throw new ArgumentNullException("DisplayName");
            }

            if (!string.IsNullOrEmpty(fieldDefinition.LoadFromJSON) && string.IsNullOrEmpty(JsonFilePath))
            {
                throw new ArgumentNullException("JsonFilePath", "You must specify a file path to the JSON file if loading from JSON");
            }

            if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName) && (siteGroups == null || siteGroups.Count() <= 0))
            {
                throw new ArgumentNullException("SiteGroups", string.Format("You must specify a collection of group for the field {0}", fieldDefinition.DisplayName));
            }

            if (string.IsNullOrEmpty(fieldDefinition.LookupListName) && fieldDefinition.fieldType == FieldType.Lookup)
            {
                throw new ArgumentNullException("LookupListName", string.Format("you must specify a lookup list title for the field {0}", fieldDefinition.DisplayName));
            }


            if (!string.IsNullOrEmpty(fieldDefinition.Description))
            {
                attributes.Add(new KeyValuePair <string, string>("Description", fieldDefinition.Description));
            }
            if (fieldDefinition.FieldIndexed)
            {
                attributes.Add(new KeyValuePair <string, string>("Indexed", fieldDefinition.FieldIndexed.ToString().ToUpper()));
            }
            if (fieldDefinition.AppendOnly)
            {
                attributes.Add(new KeyValuePair <string, string>("AppendOnly", fieldDefinition.AppendOnly.ToString().ToUpper()));
            }

            var choices = new FieldType[] { FieldType.Choice, FieldType.GridChoice, FieldType.MultiChoice, FieldType.OutcomeChoice };

            if (choices.Any(a => a == fieldDefinition.fieldType))
            {
                if (!string.IsNullOrEmpty(fieldDefinition.LoadFromJSON))
                {
                    var filePath = string.Format("{0}\\{1}", JsonFilePath, fieldDefinition.LoadFromJSON);
                    //#TODO: Check file path
                    var contents = JsonConvert.DeserializeObject <List <SPChoiceModel> >(System.IO.File.ReadAllText(filePath));
                    fieldDefinition.FieldChoices.Clear();
                    fieldDefinition.FieldChoices.AddRange(contents);
                }

                choiceXml = string.Format("<CHOICES>{0}</CHOICES>", string.Join("", fieldDefinition.FieldChoices.Select(s => string.Format("<CHOICE>{0}</CHOICE>", s.Choice.Trim())).ToArray()));
                if (!string.IsNullOrEmpty(fieldDefinition.ChoiceDefault))
                {
                    defaultChoiceXml = string.Format("<Default>{0}</Default>", fieldDefinition.ChoiceDefault);
                }
                if (fieldDefinition.fieldType == FieldType.Choice)
                {
                    attributes.Add(new KeyValuePair <string, string>("Format", fieldDefinition.ChoiceFormat.ToString("f")));
                }
            }
            else if (fieldDefinition.fieldType == FieldType.DateTime)
            {
                if (fieldDefinition.DateFieldFormat.HasValue)
                {
                    attributes.Add(new KeyValuePair <string, string>("DisplayFormat", fieldDefinition.DateFieldFormat.Value.ToString("f")));
                }
            }
            else if (fieldDefinition.fieldType == FieldType.Note)
            {
                attributes.Add(new KeyValuePair <string, string>("RichText", fieldDefinition.RichTextField.ToString().ToUpper()));
                attributes.Add(new KeyValuePair <string, string>("NumLines", fieldDefinition.NumLines.ToString()));
                if (fieldDefinition.RestrictedMode)
                {
                    attributes.Add(new KeyValuePair <string, string>("RestrictedMode", fieldDefinition.RestrictedMode.ToString().ToUpper()));
                }
                else
                {
                    attributes.Add(new KeyValuePair <string, string>("RichTextMode", "FullHtml"));
                    attributes.Add(new KeyValuePair <string, string>("IsolateStyles", true.ToString().ToUpper()));
                }
            }
            else if (fieldDefinition.fieldType == FieldType.User)
            {
                //AllowMultipleValues
                if (fieldDefinition.MultiChoice)
                {
                    attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper()));
                }
                //SelectionMode
                if (fieldDefinition.PeopleOnly)
                {
                    attributes.Add(new KeyValuePair <string, string>("UserSelectionMode", FieldUserSelectionMode.PeopleOnly.ToString("d")));
                }

                if (!string.IsNullOrEmpty(fieldDefinition.PeopleLookupField))
                {
                    attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.PeopleLookupField));
                    //fldUser.LookupField = fieldDef.PeopleLookupField;
                }
                if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName))
                {
                    var group = siteGroups.FirstOrDefault(f => f.Title == fieldDefinition.PeopleGroupName);
                    if (group != null)
                    {
                        attributes.Add(new KeyValuePair <string, string>("UserSelectionScope", group.Id.ToString()));
                    }
                }
            }
            else if (fieldDefinition.fieldType == FieldType.Lookup)
            {
                var lParentList     = host.GetAssociatedWeb().GetListByTitle(fieldDefinition.LookupListName);
                var strParentListID = lParentList.Id;

                attributes.Add(new KeyValuePair <string, string>("EnforceUniqueValues", false.ToString().ToUpper()));
                attributes.Add(new KeyValuePair <string, string>("List", strParentListID.ToString("B")));
                attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.LookupListFieldName));
            }

            var finfo = fieldDefinition.ToCreationObject();

            finfo.AdditionalAttributes = attributes;
            var finfoXml = FieldAndContentTypeExtensions.FormatFieldXml(finfo);

            if (!string.IsNullOrEmpty(choiceXml))
            {
                XDocument xd   = XDocument.Parse(finfoXml);
                XElement  root = xd.FirstNode as XElement;
                if (!string.IsNullOrEmpty(defaultChoiceXml))
                {
                    root.Add(XElement.Parse(defaultChoiceXml));
                }
                root.Add(XElement.Parse(choiceXml));
                finfoXml = xd.ToString();
            }

            return(finfoXml);
        }
        /// <summary>
        /// Process the request
        /// </summary>
        public override void ExecuteCmdlet()
        {
            base.ExecuteCmdlet();

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

            // Skip these specific fields
            var skiptypes = new FieldType[]
            {
                FieldType.Invalid,
                FieldType.Computed,
                FieldType.ContentTypeId,
                FieldType.Invalid,
                FieldType.WorkflowStatus,
                FieldType.WorkflowEventType,
                FieldType.Threading,
                FieldType.ThreadIndex,
                FieldType.Recurrence,
                FieldType.PageSeparator,
                FieldType.OutcomeChoice,
                FieldType.CrossProjectLink,
                FieldType.ModStat,
                FieldType.Error,
                FieldType.MaxItems,
                FieldType.Attachments
            };

            // 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;
            }


            // Expectation is that list already exists in target location
            foreach (var customListDefinition in siteDefinition.Lists.OrderBy(ob => ob.ProvisionOrder))
            {
                var etlList = this.ClientContext.Web.GetListByTitle(customListDefinition.ListName,
                                                                    lctx => lctx.Id, lctx => lctx.RootFolder.ServerRelativeUrl, lctx => lctx.Title);
                logger.LogInformation("List {0}", etlList.Title);


                var dataMigratedFieldModel = new SPFieldDefinitionModel(FieldType.Boolean)
                {
                    InternalName     = "DataMigrated",
                    Title            = "DataMigrated",
                    AddToDefaultView = false,
                    AutoIndexed      = true,
                    DefaultValue     = "0",
                    FieldGuid        = new Guid("9a353694-a5b4-4be4-a77a-c67bb071fbb5"),
                    FieldIndexed     = true,
                    GroupName        = "customcolumns"
                };
                var dataMigratedField = etlList.CreateListColumn(dataMigratedFieldModel, logger, null, null);

                var sourceFieldModel = new SPFieldDefinitionModel(FieldType.Integer)
                {
                    InternalName     = "SourceItemID",
                    Title            = "SourceItemID",
                    AddToDefaultView = false,
                    AutoIndexed      = true,
                    FieldGuid        = new Guid("e57a0936-5e8b-45d6-8c1c-d3e971c5b570"),
                    FieldIndexed     = true,
                    GroupName        = "customcolumns"
                };
                var sourceField = etlList.CreateListColumn(sourceFieldModel, logger, null, null);


                // pull the internal names from list definition
                var customFields = customListDefinition.FieldDefinitions
                                   .Where(lf => !skiptypes.Any(st => lf.FieldTypeKind == st))
                                   .Select(s => s.InternalName);
                logger.LogWarning("Processing list {0} found {1} fields to be processed", etlList.Title, customFields.Count());

                // enumerate list items and add them to the list
                if (customListDefinition.ListItems != null && customListDefinition.ListItems.Any())
                {
                    foreach (var item in customListDefinition.ListItems)
                    {
                        var lici    = new ListItemCreationInformation();
                        var newItem = etlList.AddItem(lici);
                        newItem[ConstantsFields.Field_Title] = item.Title;
                        newItem["SourceItemID"] = item.Id;
                        newItem["DataMigrated"] = true;
                        newItem.Update();
                        logger.LogInformation("Processing list {0} Setting up Item {1}", etlList.Title, item.Id);

                        var customColumns = item.ColumnValues.Where(cv => customFields.Any(cf => cf.Equals(cv.FieldName)));
                        foreach (var spRefCol in customColumns)
                        {
                            var internalFieldName = spRefCol.FieldName;
                            var itemColumnValue   = spRefCol.FieldValue;

                            if (IsLookup(customListDefinition, internalFieldName, out SPFieldDefinitionModel strParent))
                            {
                                newItem[internalFieldName] = GetParentItemID(this.ClientContext, itemColumnValue, strParent, logger);
                            }
                            else if (IsUser(customListDefinition, internalFieldName))
                            {
                                newItem[internalFieldName] = GetUserID(this.ClientContext, itemColumnValue, logger);
                            }
                            else
                            {
                                newItem[internalFieldName] = itemColumnValue;
                            }
                            newItem.Update();
                        }
                        etlList.Context.ExecuteQueryRetry();
                    }
                }
            }
        }
        /// <summary>
        /// Returns the parent item ID
        /// </summary>
        /// <param name="cContext"></param>
        /// <param name="ItemName"></param>
        /// <param name="ParentListColumn"></param>
        /// <param name="logger">diagnostics logger</param>
        /// <returns></returns>
        static int GetParentItemID(ClientContext cContext, dynamic ItemName, SPFieldDefinitionModel ParentListColumn, ITraceLogger logger)
        {
            int nReturn                        = -1;
            var parentListName                 = string.Empty;
            var parentListColumnName           = string.Empty;
            NativeFieldLookupValue lookupValue = null;

            try
            {
                string itemJsonString = ItemName.ToString();
                Newtonsoft.Json.Linq.JObject jobject = Newtonsoft.Json.Linq.JObject.Parse(itemJsonString);
                lookupValue = jobject.ToObject <NativeFieldLookupValue>();



                parentListName       = ParentListColumn.LookupListName;
                parentListColumnName = ParentListColumn.LookupListFieldName;
                logger.LogInformation("Start GetParentItemID {0} for column {1}", parentListName, parentListColumnName);

                Web wWeb = cContext.Web;

                var lParentList = cContext.Web.GetListByTitle(parentListName, lctx => lctx.Id, lctx => lctx.Title);
                var camlQuery   = new CamlQuery()
                {
                    ViewXml = CAML.ViewQuery(
                        CAML.Where(
                            CAML.Eq(
                                CAML.FieldValue(parentListColumnName, FieldType.Text.ToString("f"), lookupValue.LookupValue))
                            ),
                        string.Empty,
                        10
                        )
                };

                ListItemCollectionPosition itemPosition = null;
                while (true)
                {
                    var collListItem = lParentList.GetItems(camlQuery);
                    cContext.Load(collListItem, lictx => lictx.ListItemCollectionPosition);
                    cContext.ExecuteQueryRetry();
                    itemPosition = collListItem.ListItemCollectionPosition;

                    foreach (var oListItem in collListItem)
                    {
                        nReturn = oListItem.Id;
                        break;
                    }

                    // we drop out of the forloop above but if we are paging do we want to skip duplicate results
                    if (itemPosition == null)
                    {
                        break;
                    }
                }

                logger.LogInformation("Complete GetParentItemID {0} resulted in ID => {1}", parentListName, nReturn);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "Failed to query lookup value {0}", ex.Message);
            }

            return(nReturn);
        }
        /// <summary>
        /// Builds a Field Creation Info object from the Definition model and returns its resulting XML
        /// </summary>
        /// <param name="host">The instantiated web/list/library to which the field will be added</param>
        /// <param name="fieldDefinition">The definition pulled from a SP Site or user construction</param>
        /// <param name="siteGroups">The collection of site groups that a user/group field make filter</param>
        /// <param name="provisionerChoices">(OPTIONAL) The collection of hoice lookups as defined in the serialized JSON file</param>
        /// <returns></returns>
        public static string CreateFieldDefinition(this SecurableObject host, SPFieldDefinitionModel fieldDefinition, List <SPGroupDefinitionModel> siteGroups, List <SiteProvisionerFieldChoiceModel> provisionerChoices = null)
        {
            var idguid            = fieldDefinition.FieldGuid;
            var choiceXml         = string.Empty;
            var defaultChoiceXml  = string.Empty;
            var formulaXml        = string.Empty;
            var fieldReferenceXml = string.Empty;
            var attributes        = new List <KeyValuePair <string, string> >();

            if (string.IsNullOrEmpty(fieldDefinition.InternalName))
            {
                throw new ArgumentNullException("InternalName");
            }

            if (string.IsNullOrEmpty(fieldDefinition.Title))
            {
                throw new ArgumentNullException("DisplayName");
            }

            if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName) && (siteGroups == null || siteGroups.Count() <= 0))
            {
                throw new ArgumentNullException("SiteGroups", string.Format("You must specify a collection of group for the field {0}", fieldDefinition.Title));
            }

            if (string.IsNullOrEmpty(fieldDefinition.LookupListName) && fieldDefinition.FieldTypeKind == FieldType.Lookup)
            {
                throw new ArgumentNullException("LookupListName", string.Format("you must specify a lookup list title for the field {0}", fieldDefinition.Title));
            }

            if (fieldDefinition.LoadFromJSON && (provisionerChoices == null || !provisionerChoices.Any(pc => pc.FieldInternalName == fieldDefinition.InternalName)))
            {
                throw new ArgumentNullException("provisionerChoices", string.Format("You must specify a collection of field choices for the field {0}", fieldDefinition.Title));
            }


            if (!string.IsNullOrEmpty(fieldDefinition.Description))
            {
                attributes.Add(new KeyValuePair <string, string>("Description", fieldDefinition.Description.UnescapeXml().EscapeXml(true)));
            }
            if (fieldDefinition.FieldIndexed)
            {
                attributes.Add(new KeyValuePair <string, string>("Indexed", fieldDefinition.FieldIndexed.ToString().ToUpper()));
            }
            if (fieldDefinition.AppendOnly)
            {
                attributes.Add(new KeyValuePair <string, string>("AppendOnly", fieldDefinition.AppendOnly.ToString().ToUpper()));
            }

            var choices = new FieldType[] { FieldType.Choice, FieldType.GridChoice, FieldType.MultiChoice, FieldType.OutcomeChoice };

            if (choices.Any(a => a == fieldDefinition.FieldTypeKind))
            {
                if (fieldDefinition.LoadFromJSON &&
                    (provisionerChoices != null && provisionerChoices.Any(fc => fc.FieldInternalName == fieldDefinition.InternalName)))
                {
                    var choicecontents = provisionerChoices.FirstOrDefault(fc => fc.FieldInternalName == fieldDefinition.InternalName);
                    fieldDefinition.FieldChoices.Clear();
                    fieldDefinition.FieldChoices.AddRange(choicecontents.Choices);
                }

                //AllowMultipleValues
                if (fieldDefinition.MultiChoice)
                {
                    attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper()));
                }

                choiceXml = string.Format("<CHOICES>{0}</CHOICES>", string.Join("", fieldDefinition.FieldChoices.Select(s => string.Format("<CHOICE>{0}</CHOICE>", s.Choice.Trim())).ToArray()));
                if (!string.IsNullOrEmpty(fieldDefinition.ChoiceDefault))
                {
                    defaultChoiceXml = string.Format("<Default>{0}</Default>", fieldDefinition.ChoiceDefault);
                }
                if (fieldDefinition.FieldTypeKind == FieldType.Choice)
                {
                    attributes.Add(new KeyValuePair <string, string>("Format", fieldDefinition.ChoiceFormat.ToString("f")));
                }
            }
            else if (fieldDefinition.FieldTypeKind == FieldType.DateTime)
            {
                if (fieldDefinition.DateFieldFormat.HasValue)
                {
                    attributes.Add(new KeyValuePair <string, string>("Format", fieldDefinition.DateFieldFormat.Value.ToString("f")));
                }
            }
            else if (fieldDefinition.FieldTypeKind == FieldType.Note)
            {
                attributes.Add(new KeyValuePair <string, string>("RichText", fieldDefinition.RichTextField.ToString().ToUpper()));
                attributes.Add(new KeyValuePair <string, string>("RestrictedMode", fieldDefinition.RestrictedMode.ToString().ToUpper()));
                attributes.Add(new KeyValuePair <string, string>("NumLines", fieldDefinition.NumLines.ToString()));
                if (!fieldDefinition.RestrictedMode)
                {
                    attributes.Add(new KeyValuePair <string, string>("RichTextMode", "FullHtml"));
                    attributes.Add(new KeyValuePair <string, string>("IsolateStyles", true.ToString().ToUpper()));
                }
            }
            else if (fieldDefinition.FieldTypeKind == FieldType.User)
            {
                //AllowMultipleValues
                if (fieldDefinition.MultiChoice)
                {
                    attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper()));
                }
                //SelectionMode
                if (fieldDefinition.PeopleOnly)
                {
                    attributes.Add(new KeyValuePair <string, string>("UserSelectionMode", FieldUserSelectionMode.PeopleOnly.ToString("d")));
                }

                if (!string.IsNullOrEmpty(fieldDefinition.PeopleLookupField))
                {
                    attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.PeopleLookupField));
                    //fldUser.LookupField = fieldDef.PeopleLookupField;
                }
                if (!string.IsNullOrEmpty(fieldDefinition.PeopleGroupName))
                {
                    var group = siteGroups.FirstOrDefault(f => f.Title == fieldDefinition.PeopleGroupName);
                    if (group != null)
                    {
                        attributes.Add(new KeyValuePair <string, string>("UserSelectionScope", group.Id.ToString()));
                    }
                }
            }
            else if (fieldDefinition.FieldTypeKind == FieldType.Lookup)
            {
                var lParentList     = host.GetAssociatedWeb().GetListByTitle(fieldDefinition.LookupListName);
                var strParentListID = lParentList.Id;

                attributes.Add(new KeyValuePair <string, string>("EnforceUniqueValues", false.ToString().ToUpper()));
                attributes.Add(new KeyValuePair <string, string>("List", strParentListID.ToString("B")));
                attributes.Add(new KeyValuePair <string, string>("ShowField", fieldDefinition.LookupListFieldName));
                if (fieldDefinition.MultiChoice)
                {
                    attributes.Add(new KeyValuePair <string, string>("Mult", fieldDefinition.MultiChoice.ToString().ToUpper()));
                }
            }
            else if (fieldDefinition.FieldTypeKind == FieldType.Calculated)
            {
                attributes.Add(new KeyValuePair <string, string>("ResultType", fieldDefinition.OutputType.Value.ToString("f")));
                formulaXml        = string.Format("<Formula>{0}</Formula>", fieldDefinition.DefaultFormula.UnescapeXml().EscapeXml());
                fieldReferenceXml = string.Format("<FieldRefs>{0}</FieldRefs>", string.Join("", fieldDefinition.FieldReferences.Select(s => CAML.FieldRef(s.Trim())).ToArray()));
            }

            // construct the XML
            var finfo = fieldDefinition.ToCreationObject();

            finfo.AdditionalAttributes = attributes;
            var finfoXml = FieldAndContentTypeExtensions.FormatFieldXml(finfo);

            if (!string.IsNullOrEmpty(choiceXml))
            {
                XDocument xd   = XDocument.Parse(finfoXml);
                XElement  root = xd.FirstNode as XElement;
                if (!string.IsNullOrEmpty(defaultChoiceXml))
                {
                    root.Add(XElement.Parse(defaultChoiceXml));
                }
                root.Add(XElement.Parse(choiceXml));
                finfoXml = xd.ToString();
            }
            if (!string.IsNullOrEmpty(formulaXml))
            {
                XDocument xd   = XDocument.Parse(finfoXml);
                XElement  root = xd.FirstNode as XElement;
                root.Add(XElement.Parse(formulaXml));
                if (!string.IsNullOrEmpty(fieldReferenceXml))
                {
                    root.Add(XElement.Parse(fieldReferenceXml));
                }
                finfoXml = xd.ToString();
            }

            return(finfoXml);
        }
        /// <summary>
        /// Parse the Field into the portable field definition object
        /// </summary>
        /// <param name="context">The web context in which the field is provisioned</param>
        /// <param name="field">The field from which we are pulling a portable definition</param>
        /// <param name="logger">Injectable logger for writing Trace events</param>
        /// <param name="siteGroups">A collection of SharePoint groups</param>
        /// <param name="schemaXml">(OPTIONAL) the schema xml parsed into an XDocument</param>
        /// <returns></returns>
        public static SPFieldDefinitionModel RetrieveField(this ClientContext context, Field field, ITraceLogger logger, IEnumerable <Group> siteGroups = null, XElement schemaXml = null)
        {
            field.EnsureProperties(
                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.FromBaseType,
                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);

            var fieldModel = new SPFieldDefinitionModel()
            {
                FieldGuid           = field.Id,
                AutoIndexed         = field.AutoIndexed,
                CanBeDeleted        = field.CanBeDeleted,
                DefaultFormula      = field.DefaultFormula,
                DefaultValue        = field.DefaultValue,
                GroupName           = field.Group,
                Description         = field.Description,
                EnforceUniqueValues = field.EnforceUniqueValues,
                FieldTypeKind       = field.FieldTypeKind,
                FromBaseType        = field.FromBaseType,
                Filterable          = field.Filterable,
                HiddenField         = field.Hidden,
                FieldIndexed        = field.Indexed,
                InternalName        = field.InternalName,
                JSLink        = field.JSLink,
                NoCrawl       = field.NoCrawl,
                ReadOnlyField = field.ReadOnlyField,
                Required      = field.Required,
                Scope         = field.Scope,
                Title         = field.Title,
            };

            // if the schemaXML was not passed in, parse it into a node
            if (schemaXml == null)
            {
                var xdoc = XDocument.Parse(field.SchemaXml, LoadOptions.PreserveWhitespace);
                schemaXml = xdoc.Element("Field");
            }

            var fieldTypeFromXml = string.Empty;

            if (schemaXml.Attribute("Type") != null)
            {
                fieldTypeFromXml             = schemaXml.Attribute("Type").Value;
                fieldModel.FieldTypeKindText = fieldTypeFromXml;
            }

            var choices = new FieldType[] { FieldType.Choice, FieldType.GridChoice, FieldType.OutcomeChoice };

            if (field.FieldTypeKind == FieldType.DateTime)
            {
                var fieldCast = (FieldDateTime)field;
                fieldCast.EnsureProperties(
                    fc => fc.DisplayFormat,
                    fc => fc.DateTimeCalendarType,
                    fc => fc.FriendlyDisplayFormat);

                fieldModel.DateFieldFormat = fieldCast.DisplayFormat;
            }
            else if (field.FieldTypeKind == FieldType.Text)
            {
                var fieldCast = (FieldText)field;
                fieldCast.EnsureProperties(
                    fc => fc.MaxLength);

                fieldModel.MaxLength = fieldCast.MaxLength;
            }
            else if (field.FieldTypeKind == FieldType.Note)
            {
                var fieldCast = (FieldMultiLineText)field;
                fieldCast.EnsureProperties(
                    fc => fc.AllowHyperlink,
                    fc => fc.NumberOfLines,
                    fc => fc.AppendOnly,
                    fc => fc.RestrictedMode,
                    fc => fc.RichText);

                fieldModel.NumLines       = fieldCast.NumberOfLines;
                fieldModel.AppendOnly     = fieldCast.AppendOnly;
                fieldModel.RestrictedMode = fieldCast.RestrictedMode;
                fieldModel.RichTextField  = fieldCast.RichText;
            }
            else if (field.FieldTypeKind == FieldType.User)
            {
                var fieldCast = (FieldUser)field;
                fieldCast.EnsureProperties(
                    fc => fc.SelectionMode,
                    fc => fc.SelectionGroup,
                    fc => fc.AllowDisplay,
                    fc => fc.Presence,
                    fc => fc.AllowMultipleValues,
                    fc => fc.IsDependentLookup,
                    fc => fc.IsRelationship,
                    fc => fc.LookupList,
                    fc => fc.LookupField,
                    fc => fc.DependentLookupInternalNames,
                    fc => fc.PrimaryFieldId);

                fieldModel.PeopleLookupField = fieldCast.LookupField;
                fieldModel.PeopleOnly        = (fieldCast.SelectionMode == FieldUserSelectionMode.PeopleOnly);
                fieldModel.MultiChoice       = fieldCast.AllowMultipleValues;

                if (fieldCast.SelectionGroup > 0)
                {
                    var groupId = fieldCast.SelectionGroup;
                    if (siteGroups == null)
                    {
                        siteGroups = context.LoadQuery(context.Web.SiteGroups
                                                       .Where(w => w.Id == groupId).Include(group => group.Id, group => group.Title));
                        context.ExecuteQueryRetry();
                    }

                    if (siteGroups.Any(sg => sg.Id == groupId))
                    {
                        // we loaded this into context earlier
                        var groupObject = siteGroups.FirstOrDefault(fg => fg.Id == groupId);
                        fieldModel.PeopleGroupName = groupObject.Title;
                    }
                }
            }
            else if (field.FieldTypeKind == FieldType.Lookup)
            {
                var fieldCast = (FieldLookup)field;
                fieldCast.EnsureProperties(
                    fc => fc.LookupList,
                    fc => fc.LookupField,
                    fc => fc.LookupWebId,
                    fc => fc.FromBaseType,
                    fc => fc.AllowMultipleValues,
                    fc => fc.IsDependentLookup,
                    fc => fc.IsRelationship,
                    fc => fc.DependentLookupInternalNames,
                    fc => fc.PrimaryFieldId);

                if (!string.IsNullOrEmpty(fieldCast.LookupList))
                {
                    var lookupGuid = fieldCast.LookupList.TryParseGuid(Guid.Empty);
                    if (lookupGuid != Guid.Empty)
                    {
                        var fieldLookup = context.Web.Lists.GetById(lookupGuid);
                        context.Load(fieldLookup, flp => flp.Title);
                        context.ExecuteQueryRetry();

                        fieldModel.LookupListName      = fieldLookup.Title;
                        fieldModel.LookupListFieldName = fieldCast.LookupField;
                    }
                }
                fieldModel.MultiChoice = fieldCast.AllowMultipleValues;
            }
            else if (field.FieldTypeKind == FieldType.Calculated)
            {
                var fieldCast = (FieldCalculated)field;
                fieldCast.EnsureProperties(
                    fc => fc.DateFormat,
                    fc => fc.DisplayFormat,
                    fc => fc.Formula,
                    fc => fc.OutputType,
                    fc => fc.ShowAsPercentage);


                var xfieldReferences = schemaXml.Element("FieldRefs");
                if (xfieldReferences != null)
                {
                    var fieldreferences = new List <string>();
                    var xFields         = xfieldReferences.Elements("FieldRef");
                    if (xFields != null)
                    {
                        foreach (var xFieldName in xFields.Select(s => s.Attribute("Name")))
                        {
                            //   var xFieldName = xField.Attribute("Name");
                            fieldreferences.Add(xFieldName.Value);
                        }
                    }

                    fieldModel.FieldReferences = fieldreferences;
                }

                fieldModel.OutputType     = fieldCast.OutputType;
                fieldModel.DefaultFormula = fieldCast.Formula;
            }
            else if (field.FieldTypeKind == FieldType.URL)
            {
                var fieldCast = (FieldUrl)field;
                fieldCast.EnsureProperties(
                    fc => fc.DisplayFormat);

                fieldModel.UrlFieldFormat = fieldCast.DisplayFormat;
            }
            else if (field.FieldTypeKind == FieldType.MultiChoice)
            {
                var fieldCast = (FieldMultiChoice)field;
                fieldCast.EnsureProperties(
                    fc => fc.Choices,
                    fc => fc.DefaultValue,
                    fc => fc.FillInChoice,
                    fc => fc.Mappings);

                var choiceOptions = fieldCast.Choices.Select(s =>
                {
                    var optionDefault = default(Nullable <bool>);
                    if (!string.IsNullOrEmpty(field.DefaultValue) &&
                        (field.DefaultValue.Equals(s, StringComparison.CurrentCultureIgnoreCase)))
                    {
                        optionDefault = true;
                    }

                    var option = new SPChoiceModel()
                    {
                        Choice        = s,
                        DefaultChoice = optionDefault
                    };
                    return(option);
                }).ToList();

                fieldModel.FieldChoices = choiceOptions;
                fieldModel.MultiChoice  = field.FieldTypeKind == FieldType.MultiChoice;
            }
            else if (choices.Any(a => a == field.FieldTypeKind))
            {
                var fieldCast = (FieldChoice)field;
                fieldCast.EnsureProperties(
                    fc => fc.Choices,
                    fc => fc.DefaultValue,
                    fc => fc.FillInChoice,
                    fc => fc.Mappings,
                    fc => fc.EditFormat);

                var choiceOptions = fieldCast.Choices.Select(s =>
                {
                    var optionDefault = default(Nullable <bool>);
                    if (!string.IsNullOrEmpty(field.DefaultValue) &&
                        (field.DefaultValue.Equals(s, StringComparison.CurrentCultureIgnoreCase)))
                    {
                        optionDefault = true;
                    }

                    var option = new SPChoiceModel()
                    {
                        Choice        = s,
                        DefaultChoice = optionDefault
                    };
                    return(option);
                }).ToList();

                fieldModel.FieldChoices = choiceOptions;
                fieldModel.ChoiceFormat = fieldCast.EditFormat;
                fieldModel.MultiChoice  = field.FieldTypeKind == FieldType.MultiChoice;
            }
            else if (field.FieldTypeKind == FieldType.Invalid &&
                     fieldTypeFromXml.IndexOf("TaxonomyFieldType", StringComparison.InvariantCultureIgnoreCase) > -1)
            {
                var termsetproperties   = schemaXml.Element("Customization").Element("ArrayOfProperty").Elements("Property");
                var termsetpropkeyvalue = new List <KeyValuePair <string, string> >();
                foreach (var termsetproperty in termsetproperties)
                {
                    var termsetname  = termsetproperty.Element("Name");
                    var termsetvalue = termsetproperty.Element("Value");
                    termsetpropkeyvalue.Add(new KeyValuePair <string, string>(termsetname.Value, (termsetvalue != null ? termsetvalue.Value : string.Empty)));
                }

                var termSetId   = termsetpropkeyvalue.First(f => f.Key == "TermSetId");
                var termSetGuid = termSetId.Value.TryParseGuid(Guid.Empty);
                if (termSetGuid != Guid.Empty)
                {
                    var taxonomyDetails = context.GetTaxonomyFieldInfo(logger, termSetGuid);
                    taxonomyDetails.Customization  = termsetpropkeyvalue;
                    fieldModel.TaxonomyInformation = taxonomyDetails;
                }
            }


            return(fieldModel);
        }