Add a Taxonomy Field into Every Site Collection
I recently had to add a Taxonomy Site Column into a range of Site Collections, and then add the new Site Column into a Content Type. Lastly, I needed to update all libraries in the site collection to reflect the updated Content Type. How might we do this?
Step by step
Let’s get a web application, and its sites. Note that this is not the most efficient approach, as a collection of SPSites can be large. A more efficient way could be to pass the Sites through a pipeline.
$webApp=Get-Spwebapplication "http ://SharePoint" #your web app url $sites=$webApp.sites; |
Let’s loop through the SPSites, and get the SPWeb to work with. The SPSite actually has no content, nor does it have Site Columns or Content Types. The root web is where Site Columns and Content Types are managed.
for ($i=0; $i -lt $sites.count; $i++) { $site= $sites[$i]; $JPweb=$site.rootweb; } |
To do anything with Managed Metadata requires opening a Taxonomy session. This can be done directly through the Service Application. For simplicity, I open the session at the Site level. This code assumes only one Managed Metadata Service association (index offset of zero). If you have more than one MMS service application, query the collection of termstores to ensure you are grabbing the correct one. Note below there is a “group name” and “Term Set Name” required. Adjust these to match your environment. Lastly there’s a check below to ensure you grabbed a termset, and aren’t holding a null reference:
$taxSession = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site, $true); $termStore = $taxSession.TermStores[0]; $TermSet = $termStore.Groups["Your Term Group"].TermSets["TermSetName"] if ($TermSet -eq $null) { Write-Host -ForegroundColor DarkRed "Termset does not exist" continue; } |
Now let’s create a new field. Note we’ll need to know the display name for the field, as well as define a static (internal) name. As with all Site Columns, I highly recommend using a static name that avoids spaces and other characters that lead to control escape sequences in the code (%20 for space, etc). Note the termset that is “latched” to this field refers to the specific term store (it could point to any of your Managed Metadata Service Applications) and to the specific termset. These are GUIDs. Note that each Managed Metadata Service Application is associated with a dedicated database. That’s where your termsets are stored. You’ll want to select a “group” for where the site column will be displayed. We’ll add the field, and update the SPWeb object.
$taxonomyField = $JPweb.Fields.CreateNewField("TaxonomyFieldType", $FieldToAddDisplayName) $taxonomyField.SspId = $termSet.TermStore.Id $taxonomyField.TermSetId = $termSet.Id $taxonomyField.AllowMultipleValues = $false $taxonomyField.Group = "Site Column Group" $taxonomyField.StaticName = $FieldToAddStaticName $taxonomyField.ShowInEditForm = $true $taxonomyField.ShowInNewForm = $true $taxonomyField.Hidden = $false $taxonomyField.Required = $false $JPweb.Fields.Add($taxonomyField); $JPweb.Update(); |
Now let’s grab the set of Content Types, find our target Content Type and field, and update the Content Type. We’ll turn off ReadOnly for the Content Type, and do the following special object update to force propagation of the Content Type into all the libraries in the site collection: $ct.UpdateIncludingSealedAndReadOnly()
$cts=$JPWeb.ContentTypes $ct=$cts["Specific Content Type"] # replace with your content type $ct.set_ReadOnly($false) $fields=$ct.fields $fs=$JPWeb.Fields $favField=$fs.get_Item($FieldToAddDisplayName) if ($favField -eq $null) { Write-Host -ForegroundColor DarkRed "Cannot find $($FieldToAdd) in web $($JPWeb.url)" continue; } $link = new-object Microsoft.SharePoint.SPFieldLink $favField $ct.FieldLinks.Add($link) $ct.UpdateIncludingSealedAndReadOnly($true) $ct.set_ReadOnly($true) |
Let’s now put it all together into one neat script that includes some extra error handling:
$FieldToAddStaticName = "InternalFieldName" $FieldToAddDisplayName = "Field Display Name" $webApp=Get-Spwebapplication "http ://SharePoint" #your web app url $sites=$webApp.sites; for ($i=0; $i -lt $sites.count; $i++) { $site= $sites[$i]; $JPweb=$site.rootweb; if ($site.url -notlike "http ://SharePoint/MyPreferredPath/*") { continue; } $taxSession = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site, $true); $termStore = $taxSession.TermStores[0]; $TermSet = $termStore.Groups["Your Term Group"].TermSets["TermSetName"] if ($TermSet -eq $null) { Write-Host -ForegroundColor DarkRed "Termset does not exist" continue; } $taxonomyField = $JPweb.Fields.CreateNewField("TaxonomyFieldType", $FieldToAddDisplayName) $taxonomyField.SspId = $termSet.TermStore.Id $taxonomyField.TermSetId = $termSet.Id $taxonomyField.AllowMultipleValues = $false $taxonomyField.Group = "Site Column Group" $taxonomyField.StaticName = $FieldToAddStaticName $taxonomyField.ShowInEditForm = $true $taxonomyField.ShowInNewForm = $true $taxonomyField.Hidden = $false $taxonomyField.Required = $false $JPweb.Fields.Add($taxonomyField); $JPweb.Update(); $cts=$JPWeb.ContentTypes $ct=$cts["Specific Content Type"] # replace with your content type if ($ct -eq $null) { Write-Host -ForegroundColor DarkRed "Cannot add field to Content Type in web $($JPWeb.url)" continue; } $ct.set_ReadOnly($false) $fields=$ct.fields $fs=$JPWeb.Fields $favField=$fs.get_Item($FieldToAddDisplayName) if ($favField -eq $null) { Write-Host -ForegroundColor DarkRed "Cannot find $($FieldToAdd) in web $($JPWeb.url)" continue; } $link = new-object Microsoft.SharePoint.SPFieldLink $favField $ct.FieldLinks.Add($link) $ct.UpdateIncludingSealedAndReadOnly($true) $ct.set_ReadOnly($true) } |
Want to talk?
Drop us a line. We are here to answer your questions 24*7.