Showing posts with label TaxonomyField. Show all posts
Showing posts with label TaxonomyField. Show all posts

Friday, January 10, 2014

Content Organizer Rules

I had the need recently to create some content organizer rules that would route content types with specific metadata field values to specific folders within a library. To complicate matters, the metadata field value contained a taxonomy value.

I believe you cannot create such a rule via the SharePoint UI therefore I resorted to PowerShell. Let me break down how I accomplished this.
Before I do that let me outline the user background and requirement. The target library has folders within it, the primary purpose of the folders is to enable permissions granularity at the folder level. We created a new content type, named “HR Request”. This content type has a metadata field named “Request Sensitivity” which is a required selectable field of taxonomy term values like; “Corporate Executives”, “Human Resources”, “Managers”. Based on the selected value of this Sensitivity field we will route the HR Request to the folder with the correct permissions settings (i.e. we named the folders Corporate_Executives, Human_Resources, and Managers).

Let’s tackle the hardest part of this first, and that is creating the conditions string for the rule. We’ll need to have information about our field (“Request Sensitivity”) and our taxonomy term including its WssId to build the ConditionsString for our rule.

PowerShell (build a conditions string for a rule)
# Make sure the SharePoint namespace is loaded
Add-pssnapin Microsoft.SharePoint.PowerShell –erroraction silentlycontinue;

# Set some sample variables
$yourservername = "contoso.local";
$yoursitepath = "sites/Human Resources";
$yoursubweb = "Employees";

# Get an SPWeb object for the root and the subweb
$rootweb = get-spweb ("http://{0}/{1}" –f $yourservername, $yoursitepath);
$web = get-spweb ("http://{0}/{1}/{2}" –f $yourservername, $yoursitepath, $yoursubweb);

# Get our field and build the column portion of our conditions string
$field = $rootweb.Fields["Request Sensitivity"];
$column = "{0}|{1}|{2}" –f $field.Id, $field.InternalName, $field.Title;

# Get our taxonomy term
$taxSession = get-sptaxonomysession –site $rootweb.url;
$taxStore = $taxSession.TermStores[0];
$taxGroup = $taxStore.Groups["Human Resources"];
$taxTermSet = $taxGroup.TermSets["Request Sensitivity"];
$taxTerm = $taxTermSet.Terms["Corporate Executives"];

# Get the WssId for this term by querying the taxonomy hidden list
$spQuery = new-object Microsoft.SharePoint.SPQuery;
$spQuery.query = "<Where>";
$spQuery.query += "  <Eq>";
$spQuery.query += "    <FieldRef Name=’IdForTerm’ />";
$spQuery.query += "    <Value Type=’Text’>{0}</Value>" –f $taxTerm.Id;
$spQuery.query += "  </Eq>";
$spQuery.query += "</Where>";

$spList = $rootweb.lists.trygetlist("TaxonomyHiddenList");

$queryItems = $spList.getitems($spQuery);

if ($queryItems.count –gt 0) {
    $wssId = $queryItems[0]["ID"]; # If found, use it
}
else {
    $wssID = "-1";                 # Otherwise, use -1
}

# Now we can build the value portion of our conditions string
$value = "{0};#{1}|{2}" –f $wssId, $taxTerm.Name, $taxTerm.Id;

# Finally we can build the conditions string
$conditions = "<Conditions><Condition Column="{0}" Operator="IsEqual" Value="{1}" /></Conditions>" –f $column, $value;

Now that we have our conditions string built, let’s create our Organizer rule in PowerShell.

PowerShell (create a content organizer rule)
# Create an EcmDocumentRouterRule object
[Microsoft.Office.RecordsManagement.RecordsRepository.EcmDocumentRouterRule]$rule = new-object Microsoft.Office.RecordsManagement.RecordsRepository.EcmDocumentRouterRule($web);

# Set the properties of the rule
    # Set the content type the rule will apply to
    $rule.ContentTypeString = "HR Request";
    # Give the rule a name
    $rule.Name = "HR Request: Corporate Executives";
    # Give the rule some descriptive text
    $rule.Description = "Routes HR Requests with Request Sensitivity Corporate Executives to the Corporate_Executive folder.";
    # Give the rule a target path to the folder
    # The path can also be a relative server string such as:
    #    /sites/SiteName/ListTitle/FolderTitle
    $rule.TargetPath = $rootweb.SubFolders["Corporate_Executives"];
    # Since we’re not routing externally, set to false
    $rule.RouteToExternalLocation = $false;
    # Set the relative priority for the rule, in this case we want this rule to be evaluated first so we’ll use priority 3
    $rule.Priority = "3";
    # Enable the rule
    $rule.Enabled = $true;
    # Set the conditions for this rule (this is the complex part, see above for the steps to create the $conditions string
    $rule.ConditionsString = $conditions;

# Save the rule
$rule.Update();

# Release SPWebs from memory
$web.dispose();
$rootweb.dispose();

Now you say, what about a rule for “Human Resources” and “Managers”? Well, the process would be very similar for Human Resources. You would even use the same priority (eg. “3”). In our case, “Managers” is the default, so it does not need a fancy conditions string, just use “<Conditions></Conditions>” and skip all the steps I outlined above to build the conditions string, give it a lower priority (eg. “6”) and it will catch all HR Requests that are not routed by the higher priority rules.


Like so many things in SharePoint, it’s just a simple 106 step process!

Monday, December 2, 2013

SharePoint Managed Metadata Fields

The steps and rules for getting and setting Managed Metadata fields in SharePoint are not so straightforward. I created this post to help me remember what I have figured out and what works for me. I would like to give a shout out to Matthew Yarlett and his excellent post on various SharePoint field types with PowerShell. I have bookmarked his post for future reference as he covers all field types and some variations on Managed Metadata that I have not covered here.

C# (Console Application)
// <>Partial namespace listing
using Microsoft.SharePoint.Taxonomy; // Must add this reference

// Set some sample variables
string yourservername = "contoso.local";
string yoursitepath = "sites/Accounting/Audits";
string yourlistname = "Contracts";
int youritemid = 34;
string yourtaxfieldcolname = "Client";
string yourtaxsessionname = "Managed Metadata Service";
string yourtaxgroupname = "Accounting Term Store";
string yourtaxsetname = "Client Term Set";
string yournewclient = "Ford";

// <>Code omitted, insert code into Main

// Access the site object
using (SPSite site = new SPSite(string.Format("http://{0}/{1}", yourservername, yoursitepath)))
{

    // Access the web object
    using (SPWeb web = site.OpenWeb())
    {

        // Get taxonomy session variables
        TaxonomySession session = new TaxonomySession(site);
        var store = session.TermStores[yourtaxsessionname];
        var group = store.Groups[yourtaxgroupname];
        var set = group.TermSets[yourtaxsetname];

        // To get all the clients from the term set
        foreach(var term in set.Terms)
        {
            Console.WriteLine(string.Format(" – Term: {0}", term.Name));
        }
        Console.WriteLine();

        // Get a reference to a listitem
        SPList list = web.Lists.TryGetList(yourlistname);
        SPListItem item = list.GetItemById(youritemid);

        // Get the current taxonomy field value
        var taxFieldValuePrev = item[yourtaxfieldcolname] as TaxonomyFieldValue;
        Console.WriteLine(string.Format(" Previous: {0}", taxFieldValuePrev.Label));

        // Update the taxonomy field value to the new value
        var term = set.Terms[yournewclient];
        var taxField = item.Fields[yourtaxfieldcolname] as TaxonomyField;
        taxField.SetFieldValue(item, term);
        item.Update();

        // Get the updated taxonomy field value
        var taxFieldValueNew = item[yourtaxfieldcolname] as TaxonomyFieldValue;
        Console.WriteLine(string.Format(" New: {0}", taxFieldValueNew.Label));

   } // end using web

} // end using site

// Let the user terminate the program
Console.Write("Press return to quit... ");
Console.ReadLine();