Wednesday, 11 December 2013

A Quick Guide to Getting and Setting the various SPField types using C#


This article demonstrates how to set and get the various SPField types for a SharePoint list using C#.

The examples demonstrated set and get fields from an item that belongs to a custom list. The custom list contains a number of fields, and all the fields are named based on the type of field they are. For example, there is a Text field, which has been named, textfield. This is depicted in the following picture:

Applies To

The examples demonstrated below are tested with and apply to the following versions of SharePoint:
  • SharePoint 2010
  • SharePoint 2013

Get the List, and the first SPListItem

This is the basic code for getting an item. If the list has at least one item, the first item is retrieved, otherwise a new item is created.

var web = SPContext.Current.Site.RootWeb;
var list = web.Lists.TryGetList("fieldslist");
if (list == null) return;
//Get Item 1, or add a new item if the list doesn't contain any items
SPListItem item;
item = list.ItemCount > 0 ? list.Items[0] : list.Items.Add();

Create Variables used in the Examples

//Date of current update
var t = DateTime.Now.ToLongTimeString();
//StringBuilder for output
var s = new StringBuilder();
//Variable for storing temporary values
String value;

Set and Get the Title

Set the title

//Set the Title
item["Title"] = String.Format("Title updated at {0}",t);

Get the title

value = item["Title"].ToString();
s.AppendLine(String.Format("<span>Title Field: {0}</span></br>", value));

Set and Get a Text Field

Set a text field

item["textfield"] = String.Format("At {0} dogs still can't write poems", t);

Get a text field

value = item["textfield"].ToString();
s.AppendLine(String.Format("<span>Text Field: {0}</span></br>", value));

Set and Get a Note (or RichText) Field

Set a note field

item["notefield"] = String.Format("At {0} dogs still can't write poems. \r\nBut then, neither can I!", t);

Get a note field

value = item["notefield"].ToString();
s.AppendLine(String.Format("<span>Note Field: {0}</span></br>", value));

Set and Get a Yes/No Field (Boolean)

Set a yes/no field

item["yesnofield"] = false;

Get a yes/no field

value = item["yesnofield"].ToString();
s.AppendLine(String.Format("<span>Yes/No Field: {0}</span></br>", value));

Set and Get a Number Field

The type of a Number field is a Double. When you get the number from the field, you can use standard numeric format specifies to format the number for display. See Double.ToString for more information.

Set a number field

item["numberfield"] = 35;
item["numberfield"] = Double.Parse("354.67");

Get a number field

value = item["numberfield"].ToString();
s.AppendLine(String.Format("<span>Number Field: {0}</span></br>", value));
value = Double.Parse(item["numberfield"].ToString()).ToString("F1");
s.AppendLine(String.Format("<span>Number Field (one decimal place): {0}</span></br>", value));
value = Double.Parse(item["numberfield"].ToString()).ToString("F0");
s.AppendLine(String.Format("<span>Number Field (two decimal places): {0}</span></br>", value));

Set and Get a Currency (Number) Field

A currency field uses the same SharePoint field type as Number (SPFieldNumber). The type of a Number field is a Double. When you get the number from the field, you can use standard numeric format specifies to format the number for display, specifically, formatting it as a currency. See Double.ToString for more information.

Set a currency field

item["currencyfield"] = Double.Parse("354.67");

Get a currency field

value = item["currencyfield"].ToString();
s.AppendLine(String.Format("<span>Currency Field: {0}</span></br>", value));
value = Double.Parse(item["currencyfield"].ToString()).ToString("C2");
s.AppendLine(String.Format("<span>Currency Field (formatted as a currency): {0}</span></br>", value));
value = (Double.Parse(item["numberfield"].ToString()) + 123).ToString("C2");
s.AppendLine(String.Format("<span>Currency Field (addition): {0}</span></br>", value));

Set and Get a Percent (Number) Field

A percentage field uses the same SharePoint field type as Number (SPFieldNumber). The type of a Number field is a Double. When you get the number from the field, you can use standard numeric format specifies to format the number for display, specifically, formatting it as a percentage. See Double.ToString for more information.

Set a percent field

item["percentfield"] = Double.Parse("0.8735");

Get a percent field

value = item["percentfield"].ToString();
s.AppendLine(String.Format("<span>Percent Field: {0}</span></br>", value));
value = Double.Parse(item["percentfield"].ToString()).ToString("P0");
s.AppendLine(String.Format("<span>Percent Field (formatted as a percent, and as a whole number): {0}</span></br>", value));
value = Double.Parse(item["percentfield"].ToString()).ToString("P2");
s.AppendLine(String.Format("<span>Percent Field (formatted as a percent, with two decimal places): {0}</span></br>", value));

Set and Get a Date Field

To set a date field, use a System.DateTime object to create a date, then assign the DateTime object to the list item's field. When you retrieve the value of a DateTime field, you can use standard date format specifiers to format the output of the value. See DateTime.ToString for more information.

Set a date field

item["datefield"] = DateTime.Now;
//Or, set the date to Now + two days
item["datefield"] = DateTime.Now.AddDays(2);

Get a date field

value = item["datefield"].ToString();
s.AppendLine(String.Format("<span>Date Field: {0}</span></br>", value));
value = DateTime.Parse(item["datefield"].ToString()).ToString("d");
s.AppendLine(String.Format("<span>Date Field (using the \"6/15/2008\" format): {0}</span></br>", value));
value = DateTime.Parse(item["datefield"].ToString()).ToString("D");
s.AppendLine(String.Format("<span>Date Field (using the \"Sunday, June 15, 2008\" format): {0}</span></br>", value));
value = DateTime.Parse(item["datefield"].ToString()).ToString("R");
s.AppendLine(String.Format("<span>Date Field (using the \"Sun, 15 Jun 2008 21:15:07 GMT\" format): {0}</span></br>", value));
var dateValue = DateTime.Parse(item["datefield"].ToString());
value = dateValue.AddDays(13).ToString("dd-MMM-yy");
s.AppendLine(String.Format("<span>Date Field (using a custom display format): {0}</span></br>", value));

Set and Get a Choice Field

Set a choice field

item["choicefield"] = list.Fields["choicefield"].GetFieldValue("Green");
//Or, to add a new value
var choiceField = list.Fields["choicefield"] as SPFieldChoice;
if (!choiceField.Choices.Contains("Aquamarine"))
item["choicefield"] = list.Fields["choicefield"].GetFieldValue("Aquamarine");

Get a choice field

value = item["choicefield"].ToString();
s.AppendLine(String.Format("<span>Choice Field: {0}</span></br>", value));

Set and Get a Multi-Choice Field

Set a multi-choice field

var choicevalues = new SPFieldMultiChoiceValue();
item["multiplechoicefield"] = choicevalues;

Get a multi-choice field

list.Fields["multiplechoicefield"].ParseAndSetValue(item, choicevalues.ToString());
var multipleChoiceValues = new SPFieldMultiChoiceValue(item["multiplechoicefield"].ToString());
s.AppendLine(String.Format("<span>Multiple Choice Field: {0}</span></br>", multipleChoiceValues));
for (int i = 0; i <= multipleChoiceValues.Count - 1; i++)
    s.AppendLine(String.Format("<span>Multiple Choice Field, value {0}: {1}</span></br>", i, multipleChoiceValues[i]));

Set and Get a Person Field

Set a person field

item["personfield"] = web.EnsureUser("contoso\\fred");
item["personfield"] = web.EnsureUser("");

Get a person field

value = item["personfield"].ToString();
s.AppendLine(String.Format("<span>Person Field: {0}</span></br>", value));
var userFieldValue = new SPFieldUserValue(web, item["personfield"].ToString());
s.AppendLine(String.Format("<span>Person Field: Name = {0}, Email = {1}</span></br>", userFieldValue.User.Name, userFieldValue.User.Email));

Set and Get a Multi-Person Field

Set a multi-person field

var lotsofpeople = new SPFieldUserValueCollection(web, item["lotsofpeoplefield"].ToString());
var personA = web.EnsureUser("contoso\\fred");
var personAValue = new SPFieldUserValue(web, personA.ID, personA.LoginName);
var personB = web.EnsureUser("contoso\\barnie");
var personBValue = new SPFieldUserValue(web, personB.ID, personB.LoginName);
item["lotsofpeoplefield"] = lotsofpeople;

Get a multi-person field

var fieldUserValueCollection = new SPFieldUserValueCollection(web, item["lotsofpeoplefield"].ToString());
s.AppendLine(String.Format("<span>MultiPerson Field: {0}</span></br>", fieldUserValueCollection));
var userCount = 1;
foreach (SPFieldUserValue v in fieldUserValueCollection)
    s.AppendLine(String.Format("<span>MultiPerson Field, value {0}: {1}</span></br>", userCount, v.User.Name));

Set and Get a Lookup Field

Set a lookup field

var lookupField = list.Fields["lookupfield"] as SPFieldLookup;
var lookupList = web.Lists[new Guid(lookupField.LookupList)];
var lookupitem = lookupList.Items[0];
//lookupitem = lookupList.GetItemByUniqueId(new Guid("fc71b84c-74d4-4f7c-9eed-fb7a5fbe24a6"));
//lookupitem = lookupList.GetItemById(1);
var lookupValue = new SPFieldLookupValue(lookupitem.ID, lookupitem.ID.ToString());
item["lookupfield"] = lookupValue;

Get a lookup field

var lookupItemValue = new SPFieldLookupValue(item["lookupfield"].ToString());
value = lookupItemValue.LookupValue;
s.AppendLine(String.Format("<span>Lookup Field: {0}</span></br>", value));

Setting and Getting a HyperLink Field

Set a hyperlink field

var hyperlinkField = list.Fields["hyperlinkfield"] as SPFieldUrl;
var urlFieldValue = new SPFieldUrlValue();
urlFieldValue.Description = "Microsoft";
urlFieldValue.Url = "";
//SharePoint 2013 Only
hyperlinkField.ValidateParseAndSetValue(item, urlFieldValue.ToString());
//SharePoint 2010 and SharePoint 2013
hyperlinkField.ParseAndSetValue(item, urlFieldValue.ToString());

Get a hyperlink field

var hyperlinkFieldValue = new SPFieldUrlValue(item["hyperlinkfield"].ToString());
value = String.Format("<a href=\"{1}\" alt=\"{0}\">{0}</a>", hyperlinkFieldValue.Description, hyperlinkFieldValue.Url);
s.AppendLine(String.Format("<span>Hyperlink Field: {0}</span></br>", value));

Setting and Getting a Managed Metadata Field

Set a Managed Metadata field

var managedMetaDataField = list.Fields["managedmetadatafield"] as TaxonomyField;
var termsetId = managedMetaDataField.TermSetId;
var termstoreId = managedMetaDataField.SspId;
var taxonomySession = new TaxonomySession(web.Site);
var termstore = taxonomySession.TermStores[termstoreId];
var termset = termstore.GetTermSet(termsetId);
var termname = "Rubbish Tip";
var terms = termset.GetTerms(termname, false);
Term term;
if (terms.Count == 0)
    term = termset.CreateTerm(termname, termstore.Languages[0]);
    term = terms[0];
managedMetaDataField.SetFieldValue(item, term);

Get a Managed Metadata field

var taxonomyFieldValue = item["managedmetadatafield"] as TaxonomyFieldValue;
s.AppendLine(String.Format("<span>Taxonomy Field: {0} ({1})</span></br>", taxonomyFieldValue.Label, taxonomyFieldValue.TermGuid));

Setting and Getting a Multiple Valued Managed Metadata Field

Set a Multiple Valued Managed Metadata field

var managedMetaDataField = list.Fields["managedmetadatafield"] as TaxonomyField;
var termsetId = managedMetaDataField.TermSetId;
var termstoreId = managedMetaDataField.SspId;
var taxonomySession = new TaxonomySession(web.Site);
var termstore = taxonomySession.TermStores[termstoreId];
var termset = termstore.GetTermSet(termsetId);
var multipleManagedMetaDataField = list.Fields["multiplemanagedmetadatafield"] as TaxonomyField;
var termCollection = new TaxonomyFieldValueCollection(multipleManagedMetaDataField);
var taxonomyLabels = new[] {"Frog Catcher", "Giraffe Stealer", "Moon Dog"};
Term term;
foreach (var label in taxonomyLabels)
    var terms = termset.GetTerms(label, false);
    term = null;
    if (terms.Count == 0)
        term = termset.CreateTerm(label, termstore.Languages[0]);
        term = terms[0];
    var termValue = new TaxonomyFieldValue(multipleManagedMetaDataField);
    termValue.TermGuid = term.Id.ToString();
    termValue.Label = term.Name;
multipleManagedMetaDataField.SetFieldValue(item, termCollection);

Get a Multiple Valued Managed Metadata field

var taxonomyFieldValueCollection = item["multiplemanagedmetadatafield"] as TaxonomyFieldValueCollection;
value = String.Empty;
foreach (var taxonomyValue in taxonomyFieldValueCollection)
    value = String.IsNullOrEmpty(value)
                ? String.Format("{0} ({1})", taxonomyValue.Label, taxonomyValue.TermGuid)
                : String.Format("{0}, {1} ({2})", value, taxonomyValue.Label, taxonomyValue.TermGuid);
    //Or, to use get the term
    var currentTerm = termstore.GetTerm(new Guid(taxonomyValue.TermGuid));
    //do something with the term
s.AppendLine(String.Format("<span>Multiple Taxonomy Field Values: {0})</span></br>", value));

Setting and Getting a Calculated Field

Calculated fields work in a different manner to that of normal fields. A formula is set on the list field, and when a list item is added or updated, the value of the column for that list item is calculated based on the formula.

Get a Calculated Field value
Get a reference to the calculated field. Then get a reference to the list item. Finally, call the GetFieldValueAsText method, passing in the value of the item objects calculated field.

var calculatedfield = list.Fields["calculatedfield"] as SPFieldCalculated;
value = calculatedfield.GetFieldValueAsText(item["calculatedfield"]);
s.AppendLine(String.Format("<span>Calculated Field: {0}</span></br>", value));

Set the Properties of a Calculated Field
The value of a calculated field is calculated at the time a list item is created or updated. It is not possible to directly set this value. You can use the following methods to set the formula though, which is used to calculate the fields value. Before looking at these methods, there are four main properties that can be set on a calculated field; Formula, OutputType, DisplayFormat and DateFormat. Which properties you need to set, depends on the value of the calculation.
  1. Formula: The formula used to calculate the value. 
  2. OutputType: The type of the value that results from the calculation. Supported types are, Text, Number, Integer, Currency, Boolean and DateTime. 
  3. DisplayFormat: Used with number, integer and currency to specify the number of decimal places
  4. DateFormat: Used with DateTime to specify Date, or Date and Time.
In the following example, we perform the following tasks:
  1. View the current formula
  2. View the current display format
  3. Change the display format from two decimal places to four decimal places
  4. Change the output type from currency to integer
  5. Change the formula, output type and set the date format

//Configuring the calculated field
s.AppendLine(String.Format("<span>Calculated Field Formula: {0}</span></br>", calculatedfield.Formula));
s.AppendLine(String.Format("<span>Calculated Display Format: {0}</span></br>", calculatedfield.DisplayFormat));
s.AppendLine(String.Format("<span>Calculated Output Type: {0}</span></br>", calculatedfield.OutputType));
calculatedfield.DisplayFormat = SPNumberFormatTypes.FourDecimals;
s.AppendLine(String.Format("<span>Calculated Field (Display Format 4 decimals): {0}</span></br>", calculatedfield.GetFieldValueAsText(item["calculatedfield"])));
calculatedfield.OutputType = SPFieldType.Integer;
s.AppendLine(String.Format("<span>Calculated Field (Output Type Integer): {0}</span></br>", calculatedfield.GetFieldValueAsText(item["calculatedfield"])));
calculatedfield.Formula = "=[datefield]+90";
calculatedfield.DateFormat = SPDateTimeFieldFormatType.DateOnly;
calculatedfield.OutputType = SPFieldType.DateTime;
s.AppendLine(String.Format("<span>Calculated Field (Updated Formula, Date Format and Output Type): {0}</span></br>", calculatedfield.GetFieldValueAsText(item["calculatedfield"])));

See Also

Wednesday, 4 December 2013

Access Mailbox Contacts with PowerShell and EWS (Exchange Web Services)


This post deals with using PowerShell,  EWS (Exchange Web Services) and Impersonation, to get contact information for a collection of users. The example in this article demonstrates how to get contacts from a single users mailbox, while the downloadable code contains an example using functions and collections of custom objects used to store contact information to produce reports.

The basis for this code was a requirement a report of all mailbox contacts with two or more email addresses. I wrote a script that can be used to query mailboxes and recursively check all Contact folders for contacts with more than one email address. That script can be downloaded from the TechNet Gallery, here:

Otherwise, if you're just looking for an example of using PowerShell and EWS, check out the Example section below.

Example - Searching an Exchange Mailbox for all Contacts with more than one Email Address.

To work with EWS and PowerShell, you'll need to meet the following requirements

$Identity = Get-Mailbox            
$dllpath = "C:\Program Files\Microsoft\Exchange\Web Services\1.1\Microsoft.Exchange.WebServices.dll";            
$Service = new-object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2007_SP1);            
$mailAddress = $Identity.PrimarySmtpAddress.ToString();            
$enumSmtpAddress = [Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress            
$Service.ImpersonatedUserId =  New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId($enumSmtpAddress,$mailAddress);            
$propGivenName = [Microsoft.Exchange.WebServices.Data.ContactSchema]::GivenName;            
$propSurname = [Microsoft.Exchange.WebServices.Data.ContactSchema]::Surname;            
$propEmail1 = [Microsoft.Exchange.WebServices.Data.ContactSchema]::EmailAddress1;            
$propEmail2 = [Microsoft.Exchange.WebServices.Data.ContactSchema]::EmailAddress2;            
$propEmail3 = [Microsoft.Exchange.WebServices.Data.ContactSchema]::EmailAddress3;            
$propDisplayName = [Microsoft.Exchange.WebServices.Data.ContactSchema]::DisplayName;            
while ($getMoreItems)            
 $view = new-object Microsoft.Exchange.WebServices.Data.ItemView($pageSize,$pageLimitOffset,[Microsoft.Exchange.WebServices.Data.OffsetBasePoint]::Beginning);            
 $view.Traversal = [Microsoft.Exchange.WebServices.Data.ItemTraversal]::Shallow;            
 #Added properties to be returned with the query results            
 $view.PropertySet = new-object Microsoft.Exchange.WebServices.Data.PropertySet($propGivenName,$propSurname,$propEmail1,$propEmail2,$propEmail3,$propDisplayName);             
 #Added three filter properties for the contacts Email fields (there are three of them).            
 $searchFilterEmail1 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+Exists($propEmail1);            
 $searchFilterEmail2 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+Exists($propEmail2);            
 $searchFilterEmail3 = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+Exists($propEmail3);            
 #Add the filter objects to the filters collection using the OR operator            
 $searchFilters = New-Object Microsoft.Exchange.WebServices.Data.SearchFilter+SearchFilterCollection([Microsoft.Exchange.WebServices.Data.LogicalOperator]::Or);            
 #Perform the search against the default Contacts folder, and store the results in a variable            
 $contactItems = $Service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Contacts,$searchFilters,$view);            
 #Foreach contact, print the contacts display name and email addresses.            
 foreach ($item in $contactItems.Items)            
  if ($item.GetType().FullName -eq "Microsoft.Exchange.WebServices.Data.Contact")            
   Write-Host ([String]::Format("************** {0} ******************",$item.DisplayName));            
   Write-Host "First Name:"$item.GivenName;            
   Write-Host "Surname:"$item.Surname;               
   Write-Host "Email 1:"($item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress1]).Address;            
   Write-Host "Email 2:"($item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress2]).Address;            
   Write-Host "Email 2:"($item.EmailAddresses[[Microsoft.Exchange.WebServices.Data.EmailAddressKey]::EmailAddress3]).Address;               
 if ($contactItems.MoreAvailable -eq $false){$getMoreItems = $false}            
 if ($getMoreItems){$pageLimitOffset += $pageSize}             

Monday, 2 December 2013

Write Once Fields in SharePoint: A Simple Workaround.


Recently in a forum, someone had a requirement for making fields on a list read only once an item was added. Out of the box, this isn't possible.

There is a way to achieve a similar result though, using PowerShell to edit the field (or by using CAML properties when declaring the field). This solution doesn't actually set the field for a list item as read only; it just removes the field from the UI (User Interface) so it can't be edited once it's set.

The Desired Result

1. A user can add a new list item, and view all the field.

2. A user can view the list, and see all the fields.

3. The user can edit the list item, but they can only edit a limited number of fields.

How the Solution Works

The solution works by setting boolean values that determine if the field is rendered in the add, view and edit forms. By setting the ShowInNewForm or ShowInEditForm property to false, the user has no way of editing the field (other than to use the DataGrid View, which can optionally be disabled).

The PowerShell Based Solution

The following PowerShell performs the following actions:

  • Removes the "Title", "Item", "Found By" and "DateItemFound" fields from the Edit Form, so that they can't be changed once a list item has been created. 
  • Removes the "AdministrativeNotes" field from the New Form.
  • Disables the DataGrid view

$web = Get-SPWeb "http://devmy131"            
$list = $web.Lists["Lost Property"]            
$field = $list.Fields["Title"]            
$field.ShowInEditForm = $false;            
$field = $list.Fields["Item"]            
$field.ShowInEditForm = $false;            
$field = $list.Fields["FoundBy"]            
$field.ShowInEditForm = $false;            
$field = $list.Fields["DateItemFound"]            
$field.ShowInEditForm = $false;            
$field = $list.Fields["AdministrativeNotes"]            
$field.ShowInNewForm = $false;            
$list.DisableGridEditing = $true;            

The CAML Based Solution

The following CAML can be used in a List Definition (in the Schema.xml file) to set the same properties on the fields. 

<Field ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" Type="Text" Name="Title" DisplayName="Title" Required="TRUE" StaticName="Title" ShowInEditForm="FALSE" />

<Field Type="Text" DisplayName="Item" Required="TRUE" ID="{940a19c1-1dd6-4035-9107-32d159d77623}" StaticName="Item" Name="Item" ShowInEditForm="FALSE"/>

<Field Type="User" DisplayName="FoundBy" List="UserInfo" Required="TRUE" ShowField="ImnName" UserSelectionMode="PeopleOnly" UserSelectionScope="0" ID="{56142494-fe1c-48d1-89ac-5ae0901db5e5}" StaticName="FoundBy" Name="FoundBy" ShowInEditForm="FALSE"/>

<Field Type="DateTime" DisplayName="DateItemFound" Required="TRUE" Format="DateTime" FriendlyDisplayFormat="Relative" ID="{7f1ec3a8-ba55-42dd-90ca-47daae6b6cfa}" StaticName="DateItemFound" Name="DateItemFound" ShowInEditForm="FALSE"><Default>[today]</Default></Field>

<Field Type="Note" DisplayName="AdministrativeNotes" Required="FALSE" NumLines="6" RichText="TRUE" RichTextMode="FullHtml" ID="{5c5446a7-85d7-4d34-b883-f41b46968751}" StaticName="Notes" Name="Notes" RestrictedMode="TRUE" AppendOnly="TRUE" ShowInNewForm="FALSE"/>