SharePoint 2010: Creating a Folder Hierarchy Based on a Term Set with PowerShell

Long winded title, but it says it all. I recently had a need to create a nested folder hierarchy in a document library based on a managed metadata term set with almost 1,000 terms. The following PowerShell script will create a nested folder structure within a target document library based on the supplied term set.

The Script

# Outputs CSV of the specified termset from the specificed termstore/group
# Example calls:
# Create-SPFoldersFromTermSet "http://sp2010/PublicDocuments" "Documents" "Managed Metadata Service" "Enterprise Metadata" "Business Terms"

[Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Taxonomy")

function Create-SPFoldersFromTermSet(
	[string]$webUrl = $(Read-Host -prompt "Web Site URL"),
	[string]$listName = $(Read-Host -prompt "List Name"),
	[string]$termStoreName = $(Read-Host -prompt "Term Store Name"),
	[string]$termGroupName = $(Read-Host -prompt "Term Group Name"),
	[string]$termSetName = $(Read-Host -prompt "Term Set Name"))
	{

	$isValid = $true;
	$message = "";

	if ($webUrl.Length -eq 0) { $message += "`nPlease provide a web site URL"; $isValid = $false; }
	if ($listName.Length -eq 0) { $message += "`nPlease provide a list name"; $isValid = $false; }
	if ($termStoreName.Length -eq 0) { $message += "`nPlease provide a Term Store Name"; $isValid = $false; }
	if ($termGroupName.Length -eq 0) { $message += "`nPlease provide a Term Store Group Name"; $isValid = $false; }
	if ($termSetName.Length -eq 0) { $message += "`nPlease provide a Term Set Name"; $isValid = $false; }

	if ($isValid -eq $false)
	{
		write-host "`n`nERROR OCCURRED`n`t$message`n`n"
		write-host "NAME`n`tCreate-SPFoldersFromTermSet`n"
		write-host "SYNOPSIS`n`tCreates a set of folders in a destination library based on the supplied term set.`n"
		write-host "SYNTAX`n`tCreate-SPFoldersFromTermSet webUrl listName termStoreName termGroupName termSetName`n"
		write-host "EXAMPLES`n`n Create-SPFoldersFromTermSet ""http://sp2010/PublicDocuments"" ""Documents"" ""Managed Metadata Service"" ""Enterprise MetaData"" ""Business Terms""`n"
		return;
	}

	try
	{
		$ErrorActionPreference = "Stop";

		$web = $null;
		$list = $null;

		try
		{
			$web = Get-SPWeb $webUrl;
			$list = $web.Lists[$listName];

			if ($list -eq $null)
			{
				return "Unable to find a list with the name $listName"
			}
		}
		catch { "Error acquiring web/list" }

		try
		{
			$taxSession = Get-SPTaxonomySession -Site $web.Site.Url;

			try
			{
				$termStore = $taxSession.TermStores[$termStoreName];

				if ($termStore -ne $null)
				{
					try
					{
						$termGroup = $termStore.Groups[$termGroupName];

						if ($termGroup -ne $null)
						{
							try
							{
								$termSet = $termGroup.TermSets[$termSetName];

								if ($termSet -ne $null)
								{
									$rootFolder = $list.RootFolder;

									foreach ($term in $termSet.Terms)
									{
										Create-SPFolderFromTerm $rootFolder $term
									}
								}
								else
								{
									return "Termset $termSetName does not exist in the term store group $termGroupName";
								}
							}
							catch
							{
								"Unable to acquire the termset $termSetName from the term group $termGroupName"
							}
						}
						else
						{
							return "Term store group $termGroupName does not exist in the term store $termStoreName";
						}
					}
					catch
					{
						"Unable to acquire term store group $termGroupName from $termStoreName"
					}
				}
				else
				{
					return "Term store $termStoreName does not exist";
				}
			}
			catch
			{
				"Unable to acquire term store for $termStoreName"
			}
		}
		catch
		{
			"Unable to acquire session for the site $webUrl"
		}
	}
	catch
	{

	}
	finally
	{
		$ErrorActionPreference = "Continue";
	}
}

function Create-SPFolderFromTerm(
	[Microsoft.SharePoint.SPFolder]$parentFolder,
	[Microsoft.SharePoint.Taxonomy.Term]$term)
{
	$childFolder = $parentFolder.SubFolders[$term.Name];
	if ($childFolder -eq $null)
	{
		$parentFolder.SubFolders.Add($term.Name);
		$childFolder = $parentFolder.SubFolders[$term.Name];
	}

	if ($term.Terms.Count -gt 0)
	{
		foreach ($childTerm in $term.Terms)
		{
			Create-SPFolderFromTerm $childFolder $childTerm
		}
	}
}

Importing Terms from CSV in PowerShell

As the Term Store Management Tool in SharePoint 2010 does not allow for delta imports, the following PowerShell script will consume a .csv file and import the terms into the term store for the supplied term set if they do not yet exist.

File Format

Term
Sample Term 1
Sample Term 2
Sample Term 3

The Script

# Inputs CSV of the specified termset into the specificed termstore/group
# Example calls:
# Import-SPTermStoreGroupTerms "http://sp2010" "Managed Metadata Service" "Enterprise Metadata" "Business Units" "C:\Users\Me\Desktop\input.csv"

[Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Taxonomy")

function Import-SPTermStoreGroupTerms(
	[string]$siteUrl = $(Read-Host -prompt "Site Collection URL"),
	[string]$termStoreName = $(Read-Host -prompt "Term Store Name"),
	[string]$termGroupName = $(Read-Host -prompt "Term Group Name"),
	[string]$termSetName = $(Read-Host -prompt "Term Set Name"),
	[string]$inputFile = $(Read-Host -prompt "Input File (including full path)")) {

	$isValid = $true;
	$message = "";

	if ($siteUrl.Length -eq 0) { $message = "`nPlease provide a site URL"; $isValid = $false; }
	if ($termStoreName.Length -eq 0) { $message += "`nPlease provide a Term Store Name"; $isValid = $false; }
	if ($termGroupName.Length -eq 0) { $message += "`nPlease provide a Term Store Group Name"; $isValid = $false; }
	if ($termSetName.Length -eq 0) { $message += "`nPlease provide a Term Set Name"; $isValid = $false; }
	if ($inputFile.Length -eq 0) { $message += "`nPlease provide an input file"; $isValid = $false; }

	if ($isValid -eq $false) {
		write-host "`n`nERROR OCCURRED`n`t$message`n`n"
		write-host "NAME`n`tImport-SPTermStoreGroupTerms`n"
		write-host "SYNOPSIS`n`tConsumes a CSV file containing a listing of term names and creates them if needed in the specified term set.`n"
		write-host "SYNTAX`n`tImport-SPTermStoreGroupTerms siteUrl termStoreName termGroupName termSetName inputFile`n"
		write-host "EXAMPLES`n`n Import-SPTermStoreGroupTerms ""http://sp2010"" ""Managed Metadata Service"" ""Enterprise Metadata"" ""Business Units"" ""C:\Users\Me\Desktop\input.csv""`n"
		write-host "SAMPLE INPUT FILE`n`tTerm`n`tSample Term 1`n`tSample Term 2`n`tSample Term 3`n"
		return;
	}

	try {
		$ErrorActionPreference = "Stop";

		try {
			$taxSession = Get-SPTaxonomySession -Site $siteUrl;

			try {
				$termStore = $taxSession.TermStores[$termStoreName];

				if ($termStore -ne $null) {
					try {
						$termGroup = $termStore.Groups[$termGroupName];

						if ($termGroup -ne $null) {
							try {
								$termSet = $termGroup.TermSets[$termSetName];

								if ($termSet -ne $null) {
									$csv = Import-csv -path $inputFile

									if ($csv -ne $null) {
										foreach($line in $csv)
										{
											[string]$termName = $line.Term;

											if (![string]::IsNullOrEmpty($termName)) {
												$term = $null;

												try {
													[string]$normalizedTermName = [Microsoft.SharePoint.Taxonomy.TermSet]::NormalizeName($termName);
													$term = $termSet.Terms[$normalizedTermName];
													write-host "Term $termName already exists"
												}
												catch { }

												if ($term -eq $null) {
													$t = $termSet.CreateTerm($termName, 1033);
													$termSet.TermStore.CommitAll();
													write-host "Term $termName has been created"
												}
											}
										}
									}
									else {
										return "Argument supplied for input file was invalid.";
									}
								}
								else {
									return "Termset $termSetName does not exist in the term store group $termGroupName";
								}
							}
							catch {
								"Unable to acquire the termset $termSetName from the term group $termGroupName"
							}
						}
						else {
							return "Term store group $termGroupName does not exist in the term store $termStoreName";
						}
					}
					catch {
						"Unable to acquire term store group $termGroupName from $termStoreName"
					}
				}
				else {
					return "Term store $termStoreName does not exist";
				}
			}
			catch {
				"Unable to acquire term store for $termStoreName"
			}
		}
		catch {
			"Unable to acquire session for the site $siteUrl"
		}
	}
	catch { }
	finally {
		$ErrorActionPreference = "Continue";
	}
}

Export a Term Set to CSV with Identifiers in PowerShell

I recently had a need to export all of the terms from a given term set in a SharePoint 2010 Managed Metadata Service application to CSV for consumption in another process. The following PowerShell script will create a .csv file with all of the term names and identifiers for the supplied Term Store/Term Store Group/Term Set.

Updated: There was an error in the previous version of this script. It did not account for the fact that the ampersand character (“&”) is stored as a fullwidth ampersand (“\uFF06“) when a term is created. The script has been adjusted to replace any fullwidth ampersands with a basic Latin ampersand in the output.

The Script

# Outputs CSV of the specified termset from the specificed termstore/group
# Example call:
# Export-SPTermStoreGroupTerms "http://sp2010" "Managed Metadata Service" "Enterprise Metadata" "Business Units"

function Export-SPTermStoreGroupTerms {
	param (
		[string]$siteUrl = $(Read-Host -prompt "Site Collection URL"),
		[string]$termStoreName = $(Read-Host -prompt "Term Store Name"),
		[string]$termGroupName = $(Read-Host -prompt "Term Group Name"),
		[string]$termSetName = $(Read-Host -prompt "Term Set Name"),
		[string]$outPutDir = ""
	)

	$isValid = $true;
	$message = "";

	if ($siteUrl.Length -eq 0) { $message = "`nPlease provide a site URL"; $isValid = $false; }
	if ($termStoreName.Length -eq 0) { $message += "`nPlease provide a Term Store Name"; $isValid = $false; }
	if ($termGroupName.Length -eq 0) { $message += "`nPlease provide a Term Store Group Name"; $isValid = $false; }
	if ($termSetName.Length -eq 0) { $message += "`nPlease provide a Term Set Name"; $isValid = $false; }

	if ($isValid -eq $false)
	{
		write-host "`n`nERROR OCCURRED`n`t$message`n`n"
		write-host "NAME`n`tExport-SPTermStoreGroupTerms`n"
		write-host "SYNOPSIS`n`tReturns a CSV file containing a listing of term names and identifiers from the supplied term set.`n"
		write-host "SYNTAX`n`tExport-SPTermStoreGroupTerms siteUrl termStoreName termGroupName termSetName outPutDir`n"
		write-host "EXAMPLES`n`n Export-SPTermStoreGroupTerms ""http://sp2010"" ""Managed Metadata Service"" ""Enterprise Metadata"" ""Business Units""`n"
		return;
	}

	try
	{
		$ErrorActionPreference = "Stop";

		try
		{
			$site = Get-SPSite $siteUrl;
			$taxSession = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site, $true);

			try
			{
				$termStore = $taxSession.TermStores[$termStoreName];

				if ($termStore -ne $null)
				{
					try
					{
						$termGroup = $termStore.Groups[$termGroupName];

						if ($termGroup -ne $null)
						{
							try
							{
								$termSet = $termGroup.TermSets[$termSetName];

								if ($termSet -ne $null)
								{
									[string]$csvDir = "";

									if ($outPutDir.Length -gt 0)
									{
										$csvDir = $outPutDir;
									}
									else
									{
										$csvDir = $pwd;
									}

									$outPutFile = $csvDir + "\output.csv";

									$sw = new-object system.IO.StreamWriter($outPutFile);

									$sw.writeline("Name,Id");

									foreach ($term in $termSet.GetAllTerms())
									{
										[Byte[]] $ampersand = 0xEF,0xBC,0x86;

										$sw.writeline("""" + $term.Name.Replace([System.Text.Encoding]::UTF8.GetString($ampersand), "&") + """" + "," + $term.Id);
									}

									$sw.close();

									write-host "Your CSV has been created at $outPutFile";
								}
								else
								{
									return "Termset $termSetName does not exist in the term store group $termGroupName";
								}
							}
							catch
							{
								"Unable to acquire the termset $termSetName from the term group $termGroupName"
							}
						}
						else
						{
							return "Term store group $termGroupName does not exist in the term store $termStoreName";
						}
					}
					catch
					{
						"Unable to acquire term store group $termGroupName from $termStoreName"
					}
				}
				else
				{
					return "Term store $termStoreName does not exist";
				}
			}
			catch
			{
				"Unable to acquire term store for $termStoreName"
			}
		}
		catch
		{
			"Unable to acquire session for the site $siteUrl"
		}
	}
	catch
	{

	}
	finally
	{
		$ErrorActionPreference = "Continue";
	}
}

SharePoint 2007 PowerShell Profile

The following is the Powershell profile that I have been using on the SharePoint 2007 farms I administer.

############################################################################
# Assumptions:
# - Running on machine with WSS/MOSS
# - C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN in path
# - For development servers only, does not dispose of objects
############################################################################
# Example usage:
# $list = get-splist -webUrl "http://site" -listName "Announcements"
############################################################################

$12HiveDir = "${env:CommonProgramFiles}\Microsoft Shared\web server extensions\12\"

[void][reflection.assembly]::Loadwithpartialname("Microsoft.SharePoint") | out-null
[void][reflection.assembly]::Loadwithpartialname("Microsoft.Office.Server.Search") | out-null
[void][reflection.assembly]::Loadwithpartialname("Microsoft.Office.Server") | out-null

# Returns the SPWebApplication at the specified URL
function get-spwebapplication ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
    return [Microsoft.SharePoint.Administration.SPWebApplication]::Lookup("$webUrl")
}

# Returns the SPSite at the specified URL
function get-spsite ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
    return New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl"
}

# Returns the SPSite object from the specified URL
function get-spweb ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'))
{
    $site = New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl"
    return $site.OpenWeb()
}

# Returns the SPList object from the specified URL and list name
function get-splist ([String]$webUrl=$(throw 'Parameter -webUrl is missing!'),
[String]$listName=$(throw 'Parameter -listName is missing!'))
{
    $site = New-Object -TypeName "Microsoft.SharePoint.SPSite" -ArgumentList "$webUrl"
    $web = $site.OpenWeb()
    return $web.Lists[$listName]
}

Reference

Performance Optimization WordPress Plugins by W3 EDGE