Tam Tam
 

Moving a DocumentSet through code - pt1

20

Jul

One of the new features in SharePoint 2010 are the so called DocumentSets, a sort of folders-like option that allows you to manage multiple documents as they where a set, setting global metadata or capturing versions and downloading multiple documents. Since those options sounds pretty cool I recon it’s going to be a much used option within SharePoint 2010, however once you created a DocumentSet moving it around can be pretty hard, by default there are a few ways to move around your environment:

  • You can move items around in the Explorer view of your libraries, and doing so with a DocumentSet results in the copying of a folder, losing all metadata for your DocumentSet (and as you might have noticed once you set the ContentType back to DocumentSet it still shows as a folder).
  • On the other hand you can use the “send-to” option you get, but that will results in the sending of a ZIP package, still losing the information as it seems. 
  • The only way by default moving around works, is by using the Site Content and Structure.

So we decided to check if we could manage it through code. In this first part there will be some PowerShell examples on how to move a DocumentSet and where you might find yourself trying to do so, in the next part there will be some focus on how to move the DocumentSet through the ribbon, including all the metadata of it.

According to TechNet a DocumentSet is a special type of folder, and checking out MSDN shows that the the DocumentSet object does not have any options to move it to another location. The export function results in a packaged file (zip), but importing is a crime, and so far i didn't get that to work.

  1: $moveFromUrl = "aSiteUrl"
  2: $newfolder = $site.OpenWeb().GetFolder("aFolderUrl")
  3: 
  4: $movefromList=$site.OpenWeb().GetList($moveFromUrl)
  5: 
  6: $docSet = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]
  7:   ::GetDocumentSet($newfolder)  
  8: $compressedFile = $x.Export()
  9: 
 10: $compressedFile.GetType() 
 11: 
 12: $docsetID = [Microsoft.SharePoint.SPBuiltInContentTypeId]::DocumentSet
 13: $targetFolder = $movefromList.RootFolder
 14: $targetFolder.GetType()
 15: $user = $site.OpenWeb().EnsureUser("aUser")
 16: $user.GetType()
 17: 
 18: $properties = new-object System.Collections.Hashtable
 19: $properties.Add("DocumentSetDescription", "Description")
 20: 
 21: $z = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]
 22:   ::Import($compressedFile, "DocsetRestore", $targetFolder, 
 23:   $docsetID, $properties, $user);

Results in a nice error telling me nothing.

  1: IsPublic IsSerial Name                 BaseType                                                                           
  2: -------- -------- ----                 --------                                                                           
  3: True     True     Byte[]               System.Array                                                                       
  4: True     False    SPFolder             System.Object                                                                      
  5: True     False    SPUser               Microsoft.SharePoint.SPPrincipal                                                   
  6: 
  7: Exception calling "Import" with "6" argument(s): "DocID: Site prefix not set."
  8: At :line:94 char:76
  9: + $z = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]
 10:   ::Import <<<< ($compressedFile, "Docset1Backup", $targetFolder, 
 11:   $docsetID, $properties, $user);
 12: 

 

So I came up with a new approach, it is a Folder with a ContentType set to it, so I used the folder ‘MoveTo’ and updated the ContentType of the folder back to a ‘DocumentSet’, that lead to the same error I would do that through the browser, it still was a folder, without the DocumentSet welcome page set to it. After some debugging I found out that there was a field that differs between a folder and a DocumentSet: HTML File Type. So i made some changes and was able to move a DocumentSet with PowerShell. Below you can find the code, where you can see how we update the folder,in pt2 there will be some more info on how you can do so with a nice custom ribbon command, and also move all custom fields.

  1: param([string]$moveFromUrl, [string]$moveToUrl, [string]$moveItem)
  2: 
  3: [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint") 
  4: 
  5: ##########################################################################
  6: ###                                                                    ###
  7: ###                            Functions                               ###
  8: ###                                                                    ###
  9: ##########################################################################
 10: 
 11: function checkItemToMove ([Microsoft.SharePoint.SPList]$movefromList, [Microsoft.SharePoint.SPList]$movetoList, [string]$moveItem)
 12: {
 13:   $docsetID = [Microsoft.SharePoint.SPBuiltInContentTypeId]::DocumentSet
 14:   [Microsoft.SharePoint.SPFolder]$docsetToMove = $null 
 15:   
 16:   foreach($docset in $movefromList.Folders)
 17:   {  
 18:     if($docset.ContentType.ID.ToString().StartsWith($docsetID.ToString()) -and $docset.Name -eq $moveItem) 
 19:     {
 20:       $docsetToMove = $docset.Folder
 21:       $docsetContentTypeId = $docset.ContentType.Parent.Id
 22:       break;
 23:     }       
 24:   }
 25:   
 26:   if($docsetToMove -ne $null -and $docsetContentTypeId -ne $null) 
 27:   {
 28:     Write-Host -ForegroundColor Green "Found a docset: " $docsetToMove.Name " Lets move it"
 29:     moveDocSet $docsetToMove $movetoList $docsetContentTypeId
 30:   }
 31:   else {  Write-Host -ForegroundColor Red "No document set of desired name found:" $moveItem }
 32: }
 33: 
 34: function moveDocSet ([Microsoft.SharePoint.SPFolder]$docset, [Microsoft.SharePoint.SPList]$movetoList, [string]$docsetContentTypeId)
 35: {
 36:   $moveurl = $movetoList.RootFolder.ToString() + "/" + $docset.Name  
 37:   
 38:   $docset.MoveTo($moveurl)
 39:   
 40:   #retrieve it at new location
 41:   [Microsoft.SharePoint.SPFolder]$newDocset=$site.OpenWeb().GetFolder($moveurl)
 42:   if($newDocset.Exists)   
 43:   {
 44:     #update it so it is a doc set and set CT right
 45:     $newDocset.Item["ContentTypeId"] = $docsetContentTypeId
 46:     $newDocset.Item["HTML File Type"] = "SharePoint.DocumentSet" 
 47:     #TODO update all custom fields .. 
 48:     $newDocset.Item.Update()
 49:   
 50:     Write-Host -ForegroundColor Green " Docset moved succesfully ... parteh "
 51:   }
 52:   else {Write-Host -ForegroundColor Red " Failed moving the docset or setting ... "}
 53: }
 54: 
 55: ##########################################################################
 56: ###                                                                    ###
 57: ###                           /Functions                               ###
 58: ###                                                                    ###
 59: ##########################################################################
 60: 
 61: Write-Host ""
 62: Write-Host -ForegroundColor Green "Move DocSet Script v1.0 - Albert-Jan Schot "
 63: Write-Host ""
 64: 
 65: if($moveFromUrl -eq $null -or $moveFromUrl -eq "") {Write-Host -ForegroundColor Red "No folder to move from"; Exit}
 66: if($moveToUrl -eq $null -or $moveToUrl -eq "") {Write-Host -ForegroundColor Red "No folder to move to"; Exit}
 67: if($moveItem -eq $null -or $moveItem -eq "") {Write-Host -ForegroundColor Red "No DocumentSet name set"; Exit}
 68: 
 69: #Retrieves the desired objects
 70: $site=new-object Microsoft.SharePoint.SPSite($moveFromUrl)
 71: 
 72: [Microsoft.SharePoint.SPList]$movefromList=$site.OpenWeb().GetList($moveFromUrl)
 73: [Microsoft.SharePoint.SPList]$movetoList=$site.OpenWeb().GetList($moveToUrl)
 74: 
 75: #Move a docset
 76: checkItemToMove $movefromList $movetoList $moveItem 

 

There is one remark, if you try to move a DocumentSet this way to a library that does not have all the ContentTypes available that are used in the DocumentSet you will have a problem with the Version. If all ContentTypes are available it will take the version history of the DocumentSet and move it, if the ContentTypes aren’t available it will try to copy the version history, but if you try to display it, it will fail, giving a field not present error, so keep that in mind.

(Crosspost of: http://blogs.tamtam.nl/appie/2010/07/20/Moving+A+DocumentSet+Through+Code+Pt1.aspx )

Albert-Jan Schot schreef

Comments (0)

Albert-Jan Schot

Default page-layout for new pages

20

Jul

Within 2010 the ‘create page’-action always results in the same default page-layout. SharePoint 2010 allows you to determine which page-layout should be used. When the publishing feature is enabled, the user is able to choose which page-layouts and site-templates can be used. Next to this, the ‘New Page Default Settings’ allows you to choose your page-layout.

Settings

Note that this does not influence the default page-layout for site templates.

Jaap Mollema schreef

Comments (0)

Jaap Mollema

Claims Based authentication and the PublishingCache

07

Jul

If you are using Claims Based Authentication on your WebApplication then the Publishing Cache doesn't work properly.

Have a look into your Developer Dashboard to see what is going on:

The warning and critical error are:

  • 7362 - Warning Publishing Cache
  • 7363 - Critical Publishing Cache

Why is this? Because with Claims Based Authentication the Cache account cannot access the Content Databases.

The solution is to provide your SPWebApplication with two settings (Properties):

  • portalsuperuseraccount
  • portalsuperreaderaccount

If you are lazy, like me, you probably want to automate this into a PowerShell script:

Update 6 juli 2010: This script sets the default managed account as the portalsuperuseraccount and portalsuperreaderaccount. In a production scenario this will work, but it is wiser to use a read only account. Give this account Full Read permission through a Web Application Policy, follow this step-by-step-guide.

write-host ""
write-host -f White "Configure the WebApp property: portalsuperreaderaccount"
write-host ""
write-host -f Green "Stef van Hooijdonk - v1.0"
write-host ""

$snapin="Microsoft.SharePoint.PowerShell"
if (get-pssnapin $snapin -ea "silentlycontinue") {
	write-host -f Green "PSsnapin $snapin is loaded"
}
else {
	if (get-pssnapin $snapin -registered -ea "silentlycontinue") {
		write-host -f Green "PSsnapin $snapin is registered"
		Add-PSSnapin $snapin
		write-host -f Green "PSsnapin $snapin is loaded"
	}
	else {
		write-host -f Red "PSSnapin $snapin not found"
	}
}

write-host -f Green "Getting current Farm"
$farm = Get-SPFarm

write-host -f Green "Getting Default ServiceAccount (Managed)"
$cacheAccount= $farm.DefaultServiceAccount.Name

write-host ""
write-host -f Green "Going to loop Claims Based authentication WebApplications"
write-host ""

Get-SPWebApplication | foreach-object { 

	if ($_.UseClaimsAuthentication ) {
	write-host -f white $_.Url " is a Claims Based Authentication WebApp"

	write-host -f yellow " - Setting Property: portalsuperuseraccount $cacheAccount for" $_.Url
	$_.Properties["portalsuperuseraccount"] = "$cacheAccount"

	write-host -f yellow " - Setting Property: portalsuperreaderaccount $cacheAccount for" $_.Url
	$_.Properties["portalsuperreaderaccount"] = "$cacheAccount"

	$_.Update()
	write-host "Saved properties"
	}

}
Write-host ""
Write-host -f red "Going to run IISReset"
Write-host ""
IISreset /noforce
Write-host ""

 

(Crosspost of: http://stefvanhooijdonk.com/2010/07/06/claims-based-authentication-and-the-publishingcache )

Share:

Stef van Hooijdonk schreef

Comments (0)

Stef van Hooijdonk

Cannot publish pages in SharePoint 2010

25

Jun

Today my workflow gave me the following error: “The form cannot be rendered. This may be due to a misconfiguration of the Microsoft SharePoint Server State Service. For more information, contact your server administrator.”

The solution is displayed here:
http://technet.microsoft.com/nl-nl/library/ee704548%28en-us%29.aspx
Share:

Wouter Geurtzen schreef

Comments (0)

Wouter Geurtzen

Simultaneous Editing in Office 2010 Web Apps: Only in Excel and OneNote

25

Jun

Thought that this was a Major feature for the Office 2010 Web Apps. But it did not make it in the final bits for PowerPoint and Word.

"Simultaneous editing for collaboration is one of the most hyped features in Office 2010, however it’s only supported over the web in the Excel 2010 web app.  For Word and PowerPoint simultaneous editing, you’ll need to have the full client versions of the Office 2010 products.  This will likely be a disappointment for people who were hoping to collaborate on documents from kiosks anywhere in the world." (Michael Fettner)

Go over to his blog for the details.

(Crosspost of: http://stefvanhooijdonk.com/2010/06/25/simultaneous-editing-in-office-2010-web-apps-only-in-excel)

Share:

Stef van Hooijdonk schreef

Comments (0)

Stef van Hooijdonk

Login troubles with Word and SharePoint?

23

Jun

Symptom: do users complain that they need to login over and over when opening and saving word documents on your SharePoint ( MOSS2007 /SP2010 ) portal?

Then you probably have used a FQDN for your portal url.

The fix is quite easy if you have Vista or Windows 7 clients:

http://support.microsoft.com/?id=943280

Short version:

Add a reg key to "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WebClient\Parameters"

with the name: AuthForwardServerList (MULTI_STRING) and add your portal urls as values:

(Crosspost of: http://stefvanhooijdonk.com/2010/06/23/login-troubles-with-word-and-sharepoint )

Share:

Stef van Hooijdonk schreef

Comments (0)

Stef van Hooijdonk

Error while enabling Enterprise Features

21

Jun

Today we spent a lot of time figuring out how to update SharePoint 2010 from Standard to Enterprise. The Central Admin has a feature for that but it kept throwing us errors and getting us nowhere. It appeared to be that the configuration change to alter the license type has to be done by the system account, which has to be the same account that is running the SharePoint Foundation Timer Service. Besides this the account has to be a local admin on the index and all frontend servers in the farm.

Wouter Geurtzen schreef

Comments (0)

Wouter Geurtzen

Document ID Provider, the last one?

21

Jun

For a client of ours we wanted to create a Custom SP2010 Document ID Provider. For this provider I wanted to be able to adjust and configure it so I can use it for other customers also.
First I needed to know how to create a Document ID Provider and found that: Tobias Zimmergren had an excelent article on creating you own SP2010 Document ID Provider.

Next in order to create a unique sequenced number I immediatly thought of SQL Server. And found that Ton Stegeman had an equally usefull post on how to create your own SPDatabase object in a SharePoint Farm.

Now I was set to create "the last Document ID Provider" for SP2010 I was ever going to write. Perhaps not but still, it should suffice for a LOT of clients of us!

I wanted to end up with an admin page like this:

This should then result in this document id:



So how to do this?
Step 1
Create a Database with a Table where I can store my generated document id's

CREATE TABLE [dbo].[scoped_docid](
	[id] [bigint] IDENTITY(1,1) NOT NULL,
	[scopeid] [uniqueidentifier] NOT NULL,
	[objectid] [uniqueidentifier] NOT NULL,
	[scopedocid] [bigint] NULL,
	[scope] [varchar](100) NULL,
	[generateddocid] [varchar](150) NULL,
	[listid] [uniqueidentifier] NULL,
	[webid] [uniqueidentifier] NULL,
	[siteid] [uniqueidentifier] NULL,
	[webapplicationid] [uniqueidentifier] NULL,
	[farmid] [uniqueidentifier] NULL,	
	[created] [datetime] NULL,
	CONSTRAINT [PK_scoped_docid] PRIMARY KEY CLUSTERED 
(
	[id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

And a stored procedure to Get/Insert ID's:

-- =============================================
-- Author:		Stef van Hooijdonk
-- Create date: juni 2010
-- Description:	
-- =============================================
CREATE PROCEDURE GetNextScopedDocID 
	-- Add the parameters for the stored procedure here
	
	@scopeid uniqueidentifier  ,
	@scope varchar(100), 
	@itemid uniqueidentifier  
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;
	SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

	BEGIN TRANSACTION

	declare @result bigint
	declare @scopedindex bigint

	select @scopedindex=COALESCE([scopedocid],-1),@result=[id] from scoped_docid where [objectid] = lower(@itemid)
	
	if (@scopedindex is null)  begin
		-- coalesce for the first record will have MAX = null, and then we add 1
		select @scopedindex=COALESCE(MAX(scopedocid),0)+1 from scoped_docid where scope = lower(@scope)

		insert into [scoped_docid] (scopeid ,scope,objectid, scopedocid ) values( lower(@scopeid), lower(@scope),LOWER( @itemid), @scopedindex)
		select @result = SCOPE_IDENTITY()
	end
	COMMIT	
	select @result as record,@scopedindex as docid	
END
GO

There is more to it than this, but you can check out the downloads for all the details.
Step 2
Create an SPDatabase object for this Database, see the Ton Stegeman post!

Step 3
Create a Document ID Provider that uses this SPDatabase and generates Document ID's based on some settings. What I did was generate the sequenced number in SQL and then format that in a method with the other variables. Generating a YEAR or DAY into a string is fairly easy.

Step 4
Create an Central Admin page to change the settings of our Document ID Provider ( see screenshot ).
You can use the SPFarm.Local.Properties to score your settings Farm Wide:

/// <summary>
        /// The default farm wide scope setting for this DocumentProvider
        /// </summary>
        public ProviderScope Scope {
            get {
                ProviderScope result = ProviderScope.Farm;
                try {
                    string setting = Settings.GetFarmSetting("CustomDocumentIDProvider.Scope");
                    if (!string.IsNullOrEmpty(setting))
                        result = (ProviderScope)Enum.Parse(typeof(ProviderScope), setting);
                }
                catch (Exception exc) {
                        LogException(exc);
                }
                return result;
            }
            set {
                Settings.SetFarmSetting("CustomDocumentIDProvider.Scope", value.ToString());
            }
        }


The scope:

/// <summary>
/// Scopes for the Document ID Provider
/// </summary>
public enum ProviderScope {
	/// <summary>Farm wide scope</summary>
        Farm=1,
        /// <summary>Webapplication scope</summary>
        Webapplication = 2,
        /// <summary>SPSite/Site collection scope</summary>
        SiteCollection = 3,
        /// <summary>Site/Subweb (SPWeb) scope</summary>
        Site = 4,
        /// <summary>List scope</summary>
        List = 5,
        /// <summary>No scope</summary>
        None = 100
}

Downloads
Download solution
Download sources

How to use the solution

 

(Crosspost of: http://stefvanhooijdonk.com/2010/06/21/document-id-provider-the-last-one )

Share:

Stef van Hooijdonk schreef

Comments (0)

Stef van Hooijdonk

Eerste Tam Tam SharePoint 2010 portal live!

14

Jun

Tam Tam werkt sinds het begin van dit jaar aan een groot aantal SharePoint 2010 projecten, en afgelopen week is de eerste "2010" portal daadwerkelijk live gegaan!

Het betreft een omgeving voor de Solimas Groep (het overkoepelende concern voor de werkmaatschappijen: Agile Software, InfraControl en GroeneIT) waarin alle documenten met betrekking op klanten en leveranciers worden gedeeld en bovendien alle werknemers worden voorzien van in/extern nieuws, de laatste dollarkoers, informatie over collega’s en een samenwerkomgeving per afdeling. Na het beschikbaar komen van de definitieve SharePoint release in mei kon gestart worden met het inplannen van de uiteindelijke configuratie van de portal, waarvan het exacte ontwerp al compleet op de plank lag. Inmiddels is de volledige omgeving in een tijd van enkele dagen geconfigureerd. De komende weken wordt nog gewerkt aan het customizen van het grafisch ontwerp en de geautomatiseerde migratie van de duizenden voorstellen en contracten uit de oude klantomgeving, maar nu al kunnen de Solimas Groep werknemers aan de slag op hun nieuwe portal.

Kenmerkend voor dit project is dat er een aantal complexe features gerealiseerd zijn die in voorgaande versies van SharePoint een flinke dosis maatwerk hadden gevergd, maar nu met uitsluitend configuratie van nieuwe SharePoint 2010 mogelijkheden zijn opgeleverd:

  • Klantdossiers bestaan uit “Documens sets” waardoor alle documenten in een klantdossier automatisch de kenmerken van de klant overnemen zodat ze ook per stuk vindbaar zijn op bijvoorbeeld accountnaam. Het werken met document sets in dit project combineert de voordelen van het werken met slechts 1 documentbibliotheek (eenvoudig weergaves wijzigen en toevoegen voor alle dossiers, geen groot aantal bijna lege subsites) met de voordelen van een afgescheiden onderdeel per klant (elk dossier heeft een eigen voorblad met daarop de klantkenmerken en een overzicht over alle documenten).
  • Klantdossiers worden gekoppeld aan de accounts in het bestaande Microsoft Dynamics CRM systeem van de Solimas Groep. Deze “Business Connectivity Services” koppeling is tot stand gebracht door configuratie met SharePoint Designer en levert een eenvoudige gebruikersinterface op waarin de werknemers op verschillende wijzen kunnen filteren om zo snel het juiste account te kunnen koppelen. Middels een kleine (SharePoint Designer) workflow krijgt klantdossier automatisch de naam van het gekoppelde account zodat de juiste CRM naamgeving consequent wordt gebruikt in alle systemen met klantdata.
  • De documenten die toegevoegd worden aan de klantdossiers worden voorzien van een in CRM gegenereerd opportunity-ID. Ook die koppeling is via SharePoint Designer geconfigureerd en wordt in 2 stappen door de gebruiker doorlopen: eerst zoekt hij het betreffende account en vervolgens kiest hij uit de lijst met opportunities die voor die klant lopen of hebben gelopen waarbij de meest recente uiteraard bovenaan staan. Dit CRM-nummer wordt ook weer automatisch toegevoegd aan de naam van het document zodat iedereen altijd een compleet overzicht heeft welke voorstellen en contracten zijn gemaakt binnen een opportunity.
  • Aan elk document worden via de “term store” een aantal trefwoorden toegevoegd die uit een centrale taxomomie met business units, projectsoorten en contractvormen worden gekozen.
  • Via de nieuwe “metadatanavigatie” kan eenvoudig door het alfabet geklikt worden om zo snel het dossier van een van de honderden klanten te vinden. Ook kan op de trefwoorden uit de boomstructuur van de term store geklikt worden om zo uit alle klantdossiers de eerder gemaakte voorstellen en calculaties voor een bepaald type project of contract naar boven te halen.
  • Zoeken van personen en het presenteren van het profiel van een gevonden collega heeft een ware evolutiestap ondergaan en hebben we in dit project zonder enige maatwerkaanpassing kunnen implementeren.

Al met al is dit project het eerste bewijs voor wat we bij de presentatie van SharePoint 2010 in oktober in Las Vegas al vermoedden: meer functionaliteit die gebruiksvriendelijker wordt gepresenteerd wordt mogelijk met veel minder maatwerk. Projecten als deze kunnen zich meer focussen op details die van belang zijn voor de organisatie en worden in veel mindere mate gedicteerd door beperkte of dure technische mogelijkheden.

Solimas Groep: van harte gefeliciteerd met jullie nieuwe portal, en bedankt voor het gestelde vertrouwen in Tam Tam en in Microsoft, nodig om al in zeer vroeg stadium te besluiten om dit project aan te durven op een nieuw platform dat ten tijde van die beslissing nog nauwelijks in Beta-fase was beland!

Maurice Bakker schreef

Comments (1)

Maurice Bakker

SP2010 and LinkedIn working together

24

Mar

Based on an oauth example over at http://developer.linkedin.com I created a webpart for the MySite Host homepage and activity page. Here a SP2010 user can authorize SP2010 to use the LinkedIn Api on his or hers behalf.

sp2010-linkedin-webpart-networkupdates

Read more: http://stefvanhooijdonk.com/2010/03/22/sp2010-and-linkedin-workin-together/

Stef van Hooijdonk schreef

Comments (0)

Stef van Hooijdonk

Zoeken

Categorie

Archief


Sign In