Thursday, January 20, 2011

Creating Managed Metadata Termsets using PowerShell

Iterate through the XML file to dynamically create Managed Metadata Groups, Termsets and Terms using Powershell script.

Copy the XML mentioned below and save it as ManagedMetaDataTermSets.xml

<?xml version="1.0"?>
<termstore name="Managed Metadata Service">
  <group name="SharePoint Fix">
    <termset name="Region">
      <term name="North America">
        <term name="USA"></term>
        <term name="Canada"></term>
        <term name="Greenland"></term>
      </term>
      <term name="Technology">
        <term name="Technical Build and Delivery"></term>
        <term name="Technical Consultancy"></term>
        <term name="Technical Design"></term>
      </term>
      <term name="User Experience">
        <term name="Creative Design"></term>
        <term name="Information Architecture"></term>
      </term>
    </termset>
  </group>
</termstore>

The code mentioned below is RTM/Production Ready, you can find the original source code at Benn Robs site: http://sharepointtales.wordpress.com/2010/05/06/manipulating-the-terms-store-through-powershell/

Copy the code below and save it in a CreateTermSets.ps1 file: (replace the highlighted script block with your values)

Add-PsSnapin Microsoft.SharePoint.PowerShell

function SetTermsRecursive ([Microsoft.SharePoint.Taxonomy.TermSetItem] $termsetitem, $parentnode)
{
$parentnode.term
ForEach-Object {
## create the term
if($_ -ne $null)
{
$newterm = $termsetitem.CreateTerm($_.name, 1033)
Write-Host -ForegroundColor Cyan "Added term $_.name"
SetTermsRecursive $newterm $_
}
}
}
#Do not modify anything in the script from here onwards
function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

#Solutions to Deploy
$XMLName = "ManagedMetaDataTermSets.xml"
$XMLPath = Join-Path (Get-ScriptDirectory) $XMLName

echo "Extracting information from the $XMLPath"

#Site Collection URL - Give your site collection url in quotation marks
$TaxonomySiteUrl = "http://localhost"

#Access the TermStore data
[xml]$TermStoreData = Get-Content ($XMLPath)

$site = Get-SPSite $TaxonomySiteUrl
$session = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site)
$termstore = $session.TermStores[$TermStoreData.termstore.name]
$TermStoreData.termstore.group

ForEach-Object {
## create the group
if ($termstore.Groups[$_.name] -eq $null)
{
$group = $termstore.CreateGroup($_.name);
Write-Host -ForegroundColor Cyan "Added group $_.name"
$_.termset

ForEach-Object {
## create the termset
$termset = $group.CreateTermSet($_.name)
Write-Host -ForegroundColor Cyan "Added termset $_.name"
SetTermsRecursive -termsetitem $termset -parentnode $_
}
}
}

$termstore.CommitAll()
Copy code below, save it as a .bat file to automatically run the powershell script
cd /d %~dp0
powershell -noexit -file ".\CreateTermSets.ps1" "%CD%"
pause

I have created another PowerShell script that reads through the XML file and delete the respective termsets and group:

Add-PsSnapin Microsoft.SharePoint.PowerShell

#Do not modify anything in the script from here onwards
function Get-ScriptDirectory
{
 $Invocation = (Get-Variable MyInvocation -Scope 1).Value
 Split-Path $Invocation.MyCommand.Path
}

#Solutions to Deploy
$XMLName = "ManagedMetaDataTermSets.xml"
$XMLPath = Join-Path (Get-ScriptDirectory) $XMLName
echo "Extracting information from the $XMLPath"

#Site Collection URL - Give your site collection url in quotation marks
$TaxonomySiteUrl = "http://localhost"

#Access the TermStore data
[xml]$TermStoreData = Get-Content ($XMLPath)
$site = Get-SPSite $TaxonomySiteUrl
$session = new-object Microsoft.SharePoint.Taxonomy.TaxonomySession($site)
$termstore = $session.TermStores[$TermStoreData.termstore.name]

$TermStoreData.termstore.group |
 ForEach-Object {
  ## create the group
  if ($termstore.Groups[$_.name] -ne $null)
  {
    # $_.termset | ForEach-Object {
    #$termstore.Groups[$_.name].TermSet
    Write-Host -ForegroundColor Cyan "Deleted $termsetCollection"

 #Get the Term Store Group object
 $groupName = $termstore.Groups[$_.name]

 #Get Term Sets from the Group
 $groupName.TermSets | ForEach-Object {
   $_.Delete();
 }

# #Iterate through each
# foreach($termSet in $termstore.Groups[$_.name].TermSets)
# {
#  $termSet.Delete();
# }

 #Finally delete the Group
 $termstore.Groups[$_.name].Delete()
   }
  }
 $termstore.CommitAll()

I hope this helps.

Monday, December 20, 2010

Cannot connect to the configuration database - SharePoint 2007/2010

Most of the times, developers get this annoying error message, see snapshot below:


One of the common reason for this error is when MSSQLServer instance is not running, go to
Start->Run->Services.msc and start the MSSQLServer Service as shown in the snapshot below:


And then refresh your SharePoint page, it starts working perfectly fine again.

Trying to use an SPWeb object that has been closed or disposed and is no longer valid.

"Trying to use an SPWeb object that has been closed or disposed and is no longer valid" error message is very common amongst developers dealing with the SharePoint object model. Here is how the error looks like:


The reason behind this is a silly mistake that developers do, when trying to use the SPSite/SPWeb objects. Here is the bad code that resulted in the error:



I used the using clause alongwith the SPContext.Current.Site which resulted in this error, it implicilty disposes the SPSite object which should not be done when using the SPContext object. Lets refactor the code a little bit and have a look at the good code snippet which resolved this issue:



Thats about it, my code started working when I removed the using clause from the SPContext.Current.Site. The same thing is true when you try to either explicitly/implicitly Dispose the SPContext.Current.Web object. So moral of the story never dispose SPContext objects either implicitly leveraging the using clause or explicitly by using Dispose method from in your finally block.

Watch out for the SharePoint Object Model coding best practices at : http://www.sharepointfix.com/2008/12/best-practices-disposing-sharepoint.html

Javascript:ShowModalDialog Relative Site Collection URL

Get the dynamic Site Collection URL working in your Javascript code:

{SiteUrl} - Replaces the full Site Collection URL within your Javascript:ShowModalDialog Relative URL path, use this piece of code to avoid hard coding URL's in your Custom Ribbon Action's Elements.xml file,

~site - This one does the same thing but can't be used in Context of the Javascript code, and can only be used within SharePoint.

Here is a sample Elements.xml Custom Ribbon Action code, which shows how to use the {SiteUrl}  and ~site property:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<CustomAction
Id="OpenModalPopup"
RegistrationType="List"
RegistrationId="101"
Location="CommandUI.Ribbon">
<CommandUIExtension>
<CommandUIDefinitions>
<CommandUIDefinition
Location="Ribbon.Documents.New.Controls._children">
<Button
Id="Ribbon.Documents.New.Controls.DemoHelloWorldButton"
Alt="Open Modal Popup Ribbon Button"
Sequence="10"
Image32by32="/_layouts/images/SharePointFix/water.gif"
Command="OpenModalWindow"
LabelText="Update Profile Info"
TemplateAlias="o2"/>
</CommandUIDefinition>
</CommandUIDefinitions>
<CommandUIHandlers>
<CommandUIHandler Command="OpenModalWindow" CommandAction="javascript:SP.UI.ModalDialog.showModalDialog({~site/_layouts/SharePointFix/PrintListItems.aspx', title: 'Print List Items' });" />
</CommandUIHandlers>
</CommandUIExtension>
</CustomAction>
<CustomAction
Id="ExternalLink"
Description="Change your user profile country"
Location="Microsoft.SharePoint.StandardMenu"
GroupId="PersonalActions"
Sequence="0"
Title="Select Country View"
ImageUrl="~site/_layouts/images/SharePointFix/water.gif"
>
<UrlAction Url="javascript:(function () { var o = { url:'{SiteUrl}/_layouts/SharePointFix/PrintListItems.aspx', title: 'Select List Item', dialogReturnValueCallback: SP.UI.ModalDialog.RefreshPage }; SP.UI.ModalDialog.showModalDialog(o); }) ();"/>
</CustomAction>
</Elements>

Tuesday, December 7, 2010

How to go to the SharePoint Page Webpart Maintanance Mode?

There are 2 scenarios where we need the Webpart Maintanance Page to delete trouble making webparts from the current page:

a. At times the webpart we are developing might have code errors due to which the whole page hangs up or stops working entirely and redirects you to a SharePoint error message stack trace page.

b. Most of the times, we just tend to "Close" the unused webparts, while we are setting up our pages. But the webpart still remains hidden on the page and loads each time the page is called, even though not in use.

This might result in performance bottle necks, while loading the page as it loads unused webparts as well. The quickest and shortest route to fix the above is switching to the Page's Web Part Maintance Mode.

So, for eg: if your SharePoint Landing Page URL looks like this: http://sharepointfix:9999/Pages/default.aspx

In order to quickly switch to this pages webpart maintanance mode, you need to append the above URL with a ?Contents=1 query string parameter like this:
http://sharepointfix:9999/Pages/default.aspx?Contents=1

You can then delete the unused/not required webparts from this page, by checking on the webpart and clicking on the Delete option:

I hope this helps.