Jeroen Derde's Blog

My Software Engineering Universe

SharePoint TaxonomyField and “The object has been updated by another user since it was last fetched”

clock April 11, 2012 23:22 by author Jeroen Derde

Got this error after creating some taxonomy fields and then importing them into Visual Studio using CKSDev. If I then tried to connect a term to the taxonomy field the error occured.

 (“The object has been updated by another user since it was last fetched”)

This did not happen at first, but only after removing my Development Site Collection, and then deploying again from Visual Studio to a new clean sitecollection.

The error was thrown because there was a version number specified in the field xml of the taxonomy field. More detailed information can be found at: http://www.mpspartners.com/2012/02/SharePointTaxonomyFieldandTheobjecthasbeenupdatedbyanotherusersinceitwaslastfetched/



Adding WebParts and a customised CQWP webpart to a page using powershell

clock November 11, 2011 11:45 by author Jeroen Derde
Update thanks to Japser Beerens:
if ($page.File.Level -eq [Microsoft.SharePoint.SPFileLevel]::Checkout)

 changed to

if ($page.File.CheckOutType.value__ -ne 2) #2 = SPCheckOutType.None

because first statement would fail if checked-out by someone else. 

This post will descibe what you need, and what to watch out for when you are planning to add webparts to a publishing page using powershell. Scroll down and skip the plumbing part for the good bits.
First of all: get PowerGUI (or PowerGui for visual studio using the extension gallery) this will make your life a whole lot easier.
Lets start with the information we have and create a batchfile. This is not required, but makes life a lot easier when you want to execute your powershell script multiple times, or have to deal with a Sys-Op that does not know any powershell.

The case: we would like to add webparts to multiple zones on publishing pages of a portal.
We have a site we want to add webparts to: http://contoso.com
In the webpart gallery we have a custom webpart (CQWP) with the title: "Related Documents"
This webpart needs to be added to the webpartzone with zoneid called "zone1" in all pages that have a certain pagelayout.
We create a batchfile and set all the parameters we need.
PS: The script is capable of putting multiple webparts into a single zone.
 
Batchfile
echo off
SET URL="http://contoso.com"
SET WEBPARTTOADD="Related Documents"
SET ZONEID="Zone1"

powershell.exe -command .\AddWebParts.ps1 '%URL%' '%WEBPARTTOADD%' '%ZONEID%'

pause
Now we can start on the AddWebParts.ps1 file.
Create the input params
Param($siteUrl,$WebPartsToAdd,$ZoneId);
Set the pagelayoutfilenames we want to add the webparts to, and we know the zoneid exists on.
This is required because the (very)LimitedWebpartManager does not allow us to check if a webpartzone exists in a page!
If the zone does not exist, SharePoint will just put the webpart in the first zone it can find.
  
$AllowedPageLayouts = "ArticleLeft.aspx","ArticleLeft.aspx";

Add the sharepoint powershell snapin

Add-PSSnapin Microsoft.SharePoint.PowerShell

With all the plumbing done we can start on actually doing something.
function InsertWebPartInWebPartZone($siteUrl, $WebPartsToAdd, $webPartZone)
{
	# Create a new instance of the site. 
	$site = Get-SPSite (New-Object System.Uri($siteUrl)); 

	# Iterate trough all the pages
	foreach($web in $site.AllWebs)
	{ 
		Write-Host "==============================="
		Write-Host "Currently parsing" $web.Title;
		Write-Host "==============================="

		#check if we are in a publising web
		if( ! [Microsoft.SharePoint.Publishing.PublishingWeb]::IsPublishingWeb($web) )
		{
			Write-Host "Web is not a publishing web, skipping"
			continue;
		}

		# Retrieve the pages library
		$pagesLibrary = $web.Lists["Pages"];
		$allowunsafeupdates = $web.AllowUnsafeUpdates
		$web.AllowUnsafeUpdates = $true

		# Iterate through all pages
		foreach($page in $pagesLibrary.Items)
		{
			#check for null
			if($page -eq $null)
			{
				continue;
			}

			#check if page is checked out already
			#if ($page.File.Level -eq [Microsoft.SharePoint.SPFileLevel]::Checkout)
			if ($page.File.CheckOutType.value__ -ne 2) #2 = SPCheckOutType.None
			{
				Write-Host $page.Url "is Checked-Out already. Skipping
			}
			else
			{

				#check if page is a publising page and if it is of allowed pagelayouts to change
				$pubPage = [Microsoft.SharePoint.Publishing.PublishingPage]::GetPublishingPage($page)
				if( ($pubpage -ne $null) -and ($AllowedPageLayouts -contains $pubPage.Layout.Name))
				{
					Write-Host "Page is of valid layout, processing page (" $page.Name ")"
				}
				else
				{
					Write-Host "Page is of invalid layout (" $pubPage.Layout.Name "). Skipping."
					continue;
				}

				Write-Host "starting page processing -----"
				# Checking out page
				$page.File.CheckOut()

				$index = 0;
				foreach($webPartToAdd in $WebPartsToAdd)
				{
					# Retrieve the webpart from the webpartgallery
					$webPart = GetWebPartFromGallery $site $webPartToAdd;
					if($webpart -eq $null)
					{
						Write-Host "Unable to retrieve $webPartToAdd to insert. Skipping.";
						continue;
					}

					# Check if the page already contains this webpart, if so, remove it
					RemoveWebPartFromPage $page $webPart.Title;

					# Add or re-add the webpart to the page in the specified zone
					AddWebPartToPage $page $webPart $webPartZone $index;

					# Update the index
					$index++;
				}

				# Build up the message
				$checkInMessage = "This page is checked in by the Add WebPart Script";

				# Check the page in and Publish if required
				$page.File.CheckIn($checkInMessage);
			
				if($page.ParentList.EnableMinorVersions -eq $true)
				{
					$Page.File.Publish("Published");
				}
				
				Write-Host "page done"
			}
		}

	$web.AllowUnsafeUpdates = $allowunsafeupdates;

	# Dispose of the web
	$web.Dispose();
	}
}
In the previous function we called several functions, in the next section we will outline these functions 
  • GetWebPartFromGallery
  • RemoveWebPartFromPage
  • AddWebPartToPage

Get WebPartFromGallery reads a webparts XML definition. It reads the definition from the webpartgallery and finds the webpart based on the webpart name.

function GetWebPartFromGallery($site, $webPartName)
{
	Write-Host "Getting " $webPartName " from gallery."
	
	# Get the rootweb (and get the webpart gallery)
	$web = $site.OpenWeb();
	$webPartGallery = $web.Lists["Web Part Gallery"]

	if($webPartGallery -eq $null)
	{
		Write-Host("Unable to retrieve Webpartgallery");
	}

	$webpart = $null;
	foreach($wp in $webPartGallery.Items)
	{
		#find the webpart we are looking for
		if($wp.Title -eq $webPartName)
		{
			$webpart = $wp;
			Write-Host "Webpart found in gallery"
			break;
		}
	}

	if($webpart -eq $null)
	{
		Write-Host("Unable to retrieve webpart: $webPartName");
	}

	return $webpart;
}
The next two functions do all the heavy lifting in this script (the good stuff).
The first function allows us to rerun the script multiple times. This is allows us to make changed to a webpart, upload it to the gallery and replace the existing webparts with new ones on all pages.
It searched the page for a webpart with a certain title. if the webpart is found on the page, the webpart will be removed. After that the second (add) function will be called.
 
The second function adds the webpart that was read from the gallery onto the page into the specific zone.
 
Both functions contain a section (needs refactoring :) ) thats sets the HTTPContext. This is the part of the functions that is very interesting, and basically the reason for writing this blogpost.
This code was added, because when we are instantiating webparts that contain URL's (like the CQWP contains an XslItemLink, XslMainLink or XslHeaderLink ) The properties of the webpart class are used to set the values in the webpart object.
These URL properties internally call makeserverrelative and that uses the HTTP context. However, because we are running inside of powershell, these is no HttpContext. This problem does not occur with the standard SharePoint webparts I tested, because the XML definition of these webparts does not contain any URL properties. But when trying to put the customised CQWP (related documents) on the page, I got an error. After a lot of debugging manually creating a HTTPContext was the solution because of the reason stated above.
I hope this information will save someone a lot of time.
#Remove webpart based on Webpart title
function RemoveWebPartFromPage($page, $webPartTitle)
{
#make sure the page is checked-out
if ($page.File.Level -ne [Microsoft.SharePoint.SPFileLevel]::Checkout)
{
Write-Host $page.Url " is not Checked-Out. Cannot remove webpart from the page.";
return $false;
} 

 
 
# set the current httpcontext, needed for contentquerywebparts webparts that use the 
 # xslitemlink, xslmainlink or xslheaderlink property
 # else makeserverrelative url will fail, because there no context
 if ($null -eq [System.Web.HttpContext]::Current)
 {
     $sw = New-Object System.IO.StringWriter
  $resp = New-Object System.Web.HttpResponse $sw
  $req = New-Object System.Web.HttpRequest "", $web.Url, ""
  $htc = New-Object System.Web.HttpContext $req, $resp
  #explicitly cast $web to spweb object else sharepoint will 
  #see it as a PSObject, and AddWebpart wil fail
  $htc.Items["HttpHandlerSPWeb"] = $web  -as [Microsoft.SharePoint.SPweb]
  [System.Web.HttpContext]::Current = $htc
 }

$webPartCollection = $page.Web.GetWebPartCollection($page.Url,[Microsoft.SharePoint.WebPartPages.Storage]::Shared);
$webPartStorageKey = $null;
foreach($wp in $webPartCollection)
{
$webpart =  $wp -as [Microsoft.SharePoint.WebPartPages.WebPart];
if($webpart.Title -eq $webPartTitle)
{
$webPartStorageKey = $webpart.StorageKey;
break; 
}
}

if($webPartStorageKey -eq $null)
{
return $false;
}

$webPartCollection.Delete($webPartStorageKey);
return $true;
}


# Adds the desired webpart to the page
function AddWebPartToPage($page, $webPartListItem, $webpartZoneId, $index)
{ 
Write-Host "Adding" $webPartListItem.Name " to " $page.Name;

if ($page.File.Level -ne [Microsoft.SharePoint.SPFileLevel]::Checkout)
{
Write-Host $page.Url "is not Checked-Out. Cannot add webpart to the page.";
return $false;
}

# Get the webpartmanager
$wpManager = $page.Web.GetLimitedWebPartManager($page.Url,[System.Web.UI.WebControls.WebParts.PersonalizationScope]::Shared);

# Get the webpart's xml
$errorMsg = "";
$xmlReader = New-Object System.Xml.XmlTextReader($webPartListItem.File.OpenBinaryStream());
$webPart = $wpManager.ImportWebPart($xmlReader, [ref]$errorMsg) -as [Microsoft.SharePoint.WebPartPages.WebPart];

try
{
# set the current httpcontext, needed for contentquerywebparts webparts that use the 
# xslitemlink, xslmainlink or xslheaderlink property
# else makeserverrelative url will fail, because there no context
if ($null -eq [System.Web.HttpContext]::Current)
{
    $sw = New-Object System.IO.StringWriter
$resp = New-Object System.Web.HttpResponse $sw
$req = New-Object System.Web.HttpRequest "", $web.Url, ""
$htc = New-Object System.Web.HttpContext $req, $resp
#explicitly cast $web to spweb object else sharepoint will 
#see it as a PSObject, and AddWebpart wil fail
$htc.Items["HttpHandlerSPWeb"] = $web  -as [Microsoft.SharePoint.SPweb]
[System.Web.HttpContext]::Current = $htc
}

# Add webpart to the page
$wpManager.AddWebPart($webPart, $webpartZoneId, $index); 
}
catch
{
Write-Host "An error occurred. Unable to add webpart " $webPartListItem.Title;
Write-Host $_.Exception.ToString();
}
[System.Web.HttpContext]::Current = $null
$wpManager.Dispose();


return $true;
}
         
I always start a Transcript before executing the script.
Start-Transcript

InsertWebPartInWebPartZone $siteUrl $WebPartsToAdd $ZoneId

Stop-Transcript




Visio 2010 XSD

clock June 6, 2011 23:28 by author Jeroen Derde

About a week ago Microsoft published the XML Schema Definition (XSD) files for the Microsoft Visio 2010 XML Drawing (.vdx) format. This schema is also known as DatadiagramML.
This should make it alot easier to use the visio file to generate code based in the visio file.

The DatadiagramML Schema for Visio 2010 consists of three .XSD files:

  • visio.xsd is the core schema used by Visio 2003 and later
  • visio12.xsd is the set of extensions used by Visio 2007 and later
  • visio14.xsd is the set of extensions used by Visio 2010

More information about the schema is available in the Visio 2010 XML Schema Reference on MSDN.



SharePoint 2010 Workflow

clock February 25, 2010 20:24 by author Jeroen Derde

   

A collegue created a SP2010 workflow in visio, and imported it into SharePoint Designer 2010.
His flow used the following actions: 

  • AddListItemPermission
  • InheritListItemPermissions
  • RemoveListitemPermission
  • ReplaceListItemPermissions

SharePoint Designer 2010 throws an error when he validates the workflow (check for errors) or tried to deploy it.

The error (for searchablility):
This workflow action is not supported in this region of the workflow.
It can only be inserted in certain types of blocks.

 

SharePoint Designer does not show the actions as available.
After a bit of searching we found that these actions can only be added when inserted in an Impersonation Step.
This is logical as the impersonation step runs as the author of the document, in stead of the workflow starter.

Hope this is helpful.

 




Month List

Calendar

<<  December 2017  >>
MoTuWeThFrSaSu
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar

Sign in