Showing posts with label SPTaxonomyField. Show all posts
Showing posts with label SPTaxonomyField. Show all posts

Wednesday, 20 March 2013

Clear (Delete) the value of a taxonomy field using PowerShell

[Update, 3/July/2013]: I've converted this PowerShell into a script which can be downloaded from the Microsoft TechNet Gallery, here: http://gallery.technet.microsoft.com/sharepoint/Update-or-Clear-Metadata-94959cb3

The script makes it easy to clear or update the metadata values of a metadata column.

E.g.

Import-Module C:\Scripts\Update-MetadataField.ps1
$listitems = (Get-SPWeb http://devmy101).Lists["mylistwithdatainit"].Items 
Clear-MetadataField -items $listitems -MetadataFieldInternalName metadataField -ClearAllItems

[Original Article]

Yesterday I got stumped working out how to clear the value of taxonomy field when helping someone on the Microsoft forums. I could clear the value of the field using the TaxonomyField.ParseAndSetValue(item, value) method of the field, setting the value to $null, but it only worked if the list item belonged to a list. If the item was in a document library, the value wouldn't be cleared. Eventually (after a little persistence), I worked it out, and thought I'd share it here.
The proper way to clear a taxonomy field (which seems obvious upon reflection!), is to get an empty taxonomy value, using the Taxonomy.GetFieldValue method, and then pass it to the TaxonomyField.SetFieldValue method.

The only other difference between working with lists and document libraries, is the way in which we retrieve the list item.

Working with Lists
$web = get-spweb http://my
$list = $web.Lists["my list"]
$item = $list.items[1] #Get an item that currently has a value set in the Taxonomy (Managed Metadata) field
$taxField = $item.Fields["metadataField"] -as [Microsoft.SharePoint.Taxonomy.TaxonomyField] 
$taxFieldValue = $taxField.GetFieldValue("");
$taxField.SetFieldValue($item,$taxFieldValue)
$item.Update()

Working with Document Libraries
$web = get-spweb http://my
$list = $web.Lists["document library"] -as [Microsoft.SharePoint.SPDocumentLibrary]
$item = $list.items[1] #Get an item that currently has a value set in the Taxonomy (Managed Metadata) field
$url = [String]::Format("{0}{1}",$web.Url, $item.File.Url)
$file = $web.GetFile($url)
if($file.CheckOutStatus -eq "None")
{
$file.CheckOut()
$fileItem = $file.Item
$taxField = $fileItem.Fields["metadataField"] -as [Microsoft.SharePoint.Taxonomy.TaxonomyField]
$taxFieldValue = $taxField.GetFieldValue("");
$taxField.SetFieldValue($fileItem,$taxFieldValue)
$fileItem.Update()
$file.CheckIn("Updated Taxonomy Field Value")
}
else
{
$msg = [String]::Format("This file, {0}, is checked out and cannot be edited at the moment",$file.Name)
Write-Host $msg -ForegroundColor DarkYellow
}

Other tips...

Getting an item by it's ID
$item = $list.GetItemById(12)

Looping through the list
$web = get-spweb http://my
$list = $web.Lists["my list"]
$items = $list.items
$taxField = $list.Fields["metadataField"] -as [Microsoft.SharePoint.Taxonomy.TaxonomyField] 
$taxFieldValue = $taxField.GetFieldValue("");
foreach($item in $items)
{
$taxField.SetFieldValue($item,$taxFieldValue)
$item.Update()
}

Tuesday, 14 August 2012

Bulk Updating a Taxonomy Field Value on List Items with PowerShell

It's pretty easy to update the value of a taxonomy field on a collection of list items using PowerShell. Basically, you get a collection of list items, get a reference to the taxonomy field, and then loop through the items, using the SetFieldValue method of the taxonomy field to update the taxonomy field value of each item. Here's how:

1. Get the taxonomy session for the site collection

$ts = Get-SPTaxonomySession -Site http://myweb

2. Get the term store

$tstore = $ts.TermStores[0]

3. Get the term group that contains the termset for the taxonomy field you're updating.
# To list the term group names: $tstore.Groups | FT -AutoSize Name

$tgroup = $tstore.Groups["MyTermGroupName"]

4. Get the termset for the taxonomy field you're updating.
# To list the termsets: $tgroup.TermSets | FT -AutoSize Name
$tset = $tgroup.TermSets["MyTermSetName"]

5. Get the term you want to use to update the list items using the terms ID (or name).
# To list all the terms in the termset: $tset.Terms | FT -AutoSize Name,ID
# Get the term using the term name: $term = $tset.Terms["MyTermName"]

$term = $tset.Terms[[System.Guid]("f5a95261-b9a2-428b-90ce-8f85111dfd55")]

6. Get the SPWeb and List containing the list you want to update

$w = Get-SPWeb http://myweb/subsite
$l = $w.Lists["My List"]

7. Get the first list item, and use it to get a reference to the taxonomy field
$firstItem = $l.Items[0]
$tf = [Microsoft.SharePoint.Taxonomy.TaxonomyField]$firstItem.Fields["MyTaxonomyColumnName"]

8. Loop through the collection of list items and update the value

foreach($i in $l.Items){if($i.Title -like "*Presentation*"){$tf.SetFieldValue($i, $term);$i.Update();Write-host "Updated"$i.Title;}}

You could (and should) write this a little more efficiently, especially if the list is large, by using a query to get your collection of items to loop through (more efficient than looping through the entire list);

$ic = $l | ?{$_.Title -like "*Presentation*"}
foreach($i in $ic){$tf.SetFieldValue($i, $term);$i.Update();Write-host "Updated"$i.Title;}

Tuesday, 17 July 2012

Adding Taxonomy Fields to Content Types in Visual Studio

Recently I created some content types in Visual Studio to be packaged and deployed as part of a wider solution. I thought I'd document how I went about it, in case you're interested.

My solution (actually two solutions) consists of a base solution that contains all of the field definitions, and a second solution (dependant on the first) that contains the content types, list definitions, views, etc.

To create the first solution, containing the fields that will be used in the new content types:

1. Create a new Empty SharePoint project in Visual Studio

2. Add a new Empty Element to the project

3. Next, add all the field definitions that you intent to use. For my project, I added several taxonomy (managed metadata) fields, as well as a few other various fields. I keep to a couple of rules when adding fields;

Rule 1. Name all my custom fields with a prefix that identifies our organisation (in my case, this "ict")
Rule 2. Always specify the Group attribute, to logically group my fields

4.To add the taxonomy field, you need to create two field definitions, a taxonomy field, and a text field. The example below highlights the attributes I'm setting (note that I've set the FillInChoice attribute to true, to allow terms to be added to the termset via the new / edit list forms in the browser).

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
 <Field ID="{58BFD5B7-808E-4C39-ABD1-5EF402F419A9}"  
DisplayName="_Technology" Name="ictTechnology0" 
StaticName="ictTechnology0" Group="Ince Managed Fields" 
Type="Note" ShowInViewForms="FALSE" Required="FALSE" 
Hidden="TRUE" CanToggleHidden="TRUE" RowOrdinal="0" />
 <Field ID="{C3BC216A-10E6-4A52-A875-B368BF663297}" 
DisplayName="Technology" Name="ictTechnology" 
StaticName="ictTechnology" Group="Ince Managed Fields" 
Type="TaxonomyFieldType" ShowField="Term1033" FillInChoice="TRUE"/>
</Elements> 


5. Once the fields have been added, I use an feature receiver to do the rest (associate the taxonomy field to a Term Set, and associate the text field to the taxonomy field. I've seen blogs where people do this declaratively, but I prefer the feature receiver - then I can check if the termset exists, create it if it doesn't, and optionally create default terms.

The code in my feature receiver (I've scoped my feature to the Site level) looks a little like this, performing the following functions; Check the termgroup exists (create it if it doesn't), check the termset exists (create it if it doesn't), configure the fields.

Note. Make sure you add a reference to Microsoft.SharePoint.Taxonomy


public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
try
{
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Activating Ince Base Fields."), null);
using (SPSite site = properties.Feature.Parent as SPSite)
{
if (site == null)
{SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Unexpected, EventSeverity.ErrorCritical), TraceSeverity.Unexpected, String.Format("[FeatureActivation] Could not get a reference to the site. Aborting."), String.Empty);
return;}

TaxonomySession session = new TaxonomySession(site);
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Taxonomy Session: {0}", session), null);
if (session.TermStores.Count != 0)
{
var termStore = session.TermStores[0];
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Term Store: {0}", termStore.Name), null);

//Get the Term Group, creating it if it doesn't already exist
var group = GetTermGroup(termStore, "InceFunctional");
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Group: {0}", group.Name), null);

//Get the Term Set, creating it if it doesn't already exist
TermSet technologyTermSet = GetTermSet(group, "Technology", new Guid("{B71B29C9-4FBA-4FEE-9D77-77EF84C43ED2}"));
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Term Set: {0}", technologyTermSet.Name), null);

Guid fieldId = new Guid("{C3BC216A-10E6-4A52-A875-B368BF663297}"); //Technology field.
if (site.RootWeb.Fields.Contains(fieldId))
{
TaxonomyField taxonomyField = site.RootWeb.Fields[fieldId] as TaxonomyField;
if (taxonomyField == null)
{
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Taxonomy Field is null for field id: {0}.", fieldId), null);
return;
}
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Setting Taxonomy Field settings for field: {0}.", fieldId), null);

//Associate the taxonomy field to the termset.
taxonomyField.SspId = technologyTermSet.TermStore.Id;
taxonomyField.AnchorId = Guid.Empty;
taxonomyField.TermSetId = technologyTermSet.Id;
taxonomyField.AllowMultipleValues = true;

//Configure the taxonomy field to allow terms to be added via the form
taxonomyField.CreateValuesInEditForm = true;
//Associate the text field to the taxonomy field.
taxonomyField.TextField = new Guid("{58BFD5B7-808E-4C39-ABD1-5EF402F419A9}");
taxonomyField.Update();
}}}}
catch (Exception e)
{
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Unexpected, EventSeverity.ErrorCritical), TraceSeverity.Unexpected, String.Format("[FeatureActivation] Unexpected error activating Ince Base Fields solution. Error: {0}", e.Message), e.StackTrace);
}}

private static TermSet GetTermSet(Group group, String termsetName, Guid termsetId)
{
try
{
foreach (TermSet set in group.TermSets)
{
if (set.Name.ToLower().Equals(termsetName.ToLower()))
{return set;}
}
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Termset does not exist. Creating Termset. "), null);
var termSet = group.CreateTermSet(termsetName, termsetId, 1033);
group.TermStore.CommitAll();
return termSet;
}
catch (Exception e)
{
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Unexpected, EventSeverity.ErrorCritical), TraceSeverity.Unexpected, String.Format("[FeatureActivation] Unexpected error activating ITContentTypes solution. Error: {0}", e.Message), e.StackTrace);
throw new Exception("[GetTermSet] Exception getting term set.");
}}

private static Group GetTermGroup(TermStore store, string groupName)
{
try
{
foreach (Group g in store.Groups)
{
if (g.Name.ToLower().Equals(groupName.ToLower()))
{
return g;
}}
SPDiagnosticsService.Local.WriteTrace(0, new SPDiagnosticsCategory("Ince.BaseFields", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, String.Format("[FeatureActivation] Group does not exist. Creating Group. "), null);
store.CreateGroup(groupName);
store.CommitAll();
return store.Groups[groupName];
}
catch (Exception)
{
throw new Exception("[GetTermGroup] Exception getting term store group.");
}}


6. Build and package the solution, then deploy it.

7. The next step is creating a content type that uses the taxonomy field. To do this I've created a new Empty SharePoint Project, and added a new Content Type to the project. I've based mine on an Item.

8. Open the Elements.xml file created for the content type, and add field references to (among others) your new taxonomy fields.

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- Parent ContentType: Item (0x01) -->
<ContentType ID="0x0100d8cf45e3ef6a4044a6b9dea877e4617f"
   Name="IT Item"
   Group="Ince"
   Description="A list for tracking IT ideas or issues."
   Inherits="TRUE"
   Version="0">
<FieldRefs>
  <FieldRef ID="{fa564e0f-0c70-4ab9-b863-0177e6ddd247}" 
  DisplayName="Title"/>
  <FieldRef ID="{C6F3AEEB-1ADE-43CB-81BA-828D38E23D78}" 
  DisplayName="_Project" Name="ictProjectName0"/>
  <FieldRef ID="{75335227-12FD-4376-935F-30C2A57B1AB5}" 
  DisplayName="Project" Name="ictProjectName" Required="FALSE" />
  <FieldRef ID="{58BFD5B7-808E-4C39-ABD1-5EF402F419A9}" 
  DisplayName="_Technology" Name="ictTechnology0"/>
  <FieldRef ID="{C3BC216A-10E6-4A52-A875-B368BF663297}" 
  DisplayName="Technology" Name="ictTechnology" Required="FALSE" />
  <FieldRef ID="{53101f38-dd2e-458c-b245-0c236cc13d1a}" 
  DisplayName="Assigned To" />
  <FieldRef ID="{9da97a8a-1da5-4a77-98d3-4bc10456e700}" 
  DisplayName="Description" NumLines="10"/>
  <FieldRef ID="{c15b34c3-ce7d-490a-b133-3f4de8801b76}" 
  DisplayName="Status"/>
</FieldRefs>
</ContentType>
</Elements> 


9. Bobs your uncle (that means it's finished - deploy it and away you go!). Some other things you might want to consider; adding an activation depency on the first solution, and adding some list definitions to your solution that use the content type.