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

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

Coding against a Document Set

16

Nov

I’ve just had a 5 day training on development for SharePoint 2010. We’ve seen some cool stuff, were able to do some Hands on Labs and talk to other SharePoint experts about the new stuff that is coming up.

One of the best things though about this training was the ability to try some stuff out for yourself. The fact that no project managers or customers were bothering me for a week allowed me to finally take the time to look around in the object model, the central admin and the new front end interfaces.

Over the next few week I’ll be publishing some post on the things I’ve tried out. I hope to publish a lot more posts about SP2010 once Beta 2 comes available.

 

DISCLAIMER: The examples are build on and tested against a Beta 1 build of SharePoint 2010 and a Beta 1 build of Visual Studio 2010, so there is no guarantee this will work on later versions.

 

One of the things I was eager to try out is the new Document Sets feature. Document Sets allow you to group related documents together and share metadata between those docs. When you view a document set in a library, you are presented with a welcome page that shows the metadata of the set and the contents.

The welcome page in itself is something you’re able to customize. So you can add web parts and other controls through the interface or SharePoint Designer to the welcome page.

 

First let me start by giving you some code you can use to show extra information about the document set in a web part you can place on the welcome page:

   1: try
   2: {
   3:     SPListItem item = SPContext.Current.ListItem;
   4:  
   5:     DocumentSet set = DocumentSet.GetDocumentSet(item.Folder);
   6:  
   7:     writer.WriteLine("ContentType: {0}<br/>", item.ContentType.Name);
   8:     writer.WriteLine("Title: {0}<br/>", item.Title);
   9:     writer.WriteLine("WelcomePageUrl: {0}<br/>", set.WelcomePageUrl);
  10:     writer.WriteLine("ItemCount: {0}<br/>", set.Folder.ItemCount);
  11:     writer.WriteLine("Welcomepage Fields:<br/>");
  12:     DocumentSetTemplate template = set.ContentTypeTemplate;
  13:     WelcomePageFieldCollection fields = template.WelcomePageFields;
  14:     foreach (SPField field in fields)
  15:     {
  16:         writer.WriteLine("{0}<br/>", field.Title);
  17:     }
  18: }
  19: catch (Exception)
  20: { }

First we get a reference to the current List Item through the SPContext. This list item is the main item for the document set that contains the metadata that is pushed into the child documents.

We then can get a reference to the DocumentSet by passing in the SPFolder of the item into a static method of the DocumentSet class. The DocumentSet class is stored in the Microsoft.Office.DocumentManagement.dll in the DocumentSets namespace.

The DocumentSetTemplate in turn contains more information about the fields that are shared or shown on the Welcome page.

 

In the next post I’ll show you how to provision a document set from a feature. Something that is quite easy to do with the new SharePoint project and item templates for Visual Studio 2010.

Peter Gerritsen schreef

Comments (0)

Peter Gerritsen

Provisioning a Document Set

16

Nov

In this post I’ll show you how to create a project in Visual Studio 2010 with the new SharePoint project and item templates to provision a Document Set from a feature.

DISCLAIMER: The examples are build on and tested against a Beta 1 build of SharePoint 2010 and a Beta 1 build of Visual Studio 2010, so there is no guarantee this will work on later versions or even on the Beta 1 build you're running.

A Document Set is basically a content type just like all the others you can find in SharePoint, it derives from the Folder content type. So the steps you need to take to provision a Document Set content type are not that different as well.

We’ll start out by creating an empty SharePoint project in Visual Studio 2010 and work from there.

First we’ll add a Content Type item to the project. In the elements.xml file we place the following content:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
   3:   <ContentType ID="0x0120D520002228EBDE71841343B23171CE351F7D39" Name="Test Doc Set" Group="Document Set Content Types" Version="2" ProgId="SharePoint.DocumentSet">
   4:     <Folder TargetName="_cts/Test Doc Set" />
   5:     <FieldRefs>
   6:       <FieldRef ID="{038d1503-4629-40f6-adaf-b47d1ab2d4fe}" Name="Company" />
   7:     </FieldRefs>
   8:     <XmlDocuments>
   9:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/events">
  10:         <spe:Receivers xmlns:spe="http://schemas.microsoft.com/sharepoint/events">
  11:           <Receiver>
  12:             <Name>DocumentSet ItemUpdated</Name>
  13:             <Synchronization>Synchronous</Synchronization>
  14:             <Type>10002</Type>
  15:             <SequenceNumber>100</SequenceNumber>
  16:             <Assembly>Microsoft.Office.DocumentManagement, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
  17:             <Class>Microsoft.Office.DocumentManagement.DocumentSets.DocumentSetEventReceiver</Class>
  18:             <Data />
  19:             <Filter />
  20:           </Receiver>
  21:           <Receiver>
  22:             <Name>DocumentSet ItemAdded</Name>
  23:             <Synchronization>Synchronous</Synchronization>
  24:             <Type>10001</Type>
  25:             <SequenceNumber>100</SequenceNumber>
  26:             <Assembly>Microsoft.Office.DocumentManagement, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
  27:             <Class>Microsoft.Office.DocumentManagement.DocumentSets.DocumentSetItemsEventReceiver</Class>
  28:             <Data />
  29:             <Filter />
  30:           </Receiver>
  31:         </spe:Receivers>
  32:       </XmlDocument>
  33:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes">
  34:         <act:AllowedContentTypes xmlns:act="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes" LastModified="11/4/2009 3:30:17 PM">
  35:           <AllowedContentType id="0x0101" />
  36:         </act:AllowedContentTypes>
  37:       </XmlDocument>
  38:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/sharedfields">
  39:         <sf:SharedFields xmlns:sf="http://schemas.microsoft.com/office/documentsets/sharedfields" LastModified="11/4/2009 3:31:50 PM">
  40:           <SharedField id="cbb92da4-fd46-4c7d-af6c-3128c2a5576e" />
  41:           <SharedField id="038d1503-4629-40f6-adaf-b47d1ab2d4fe" />
  42:         </sf:SharedFields>
  43:       </XmlDocument>
  44:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/welcomepagefields">
  45:         <wpf:AllowedContentTypes xmlns:wpf="http://schemas.microsoft.com/office/documentsets/welcomepagefields" LastModified="11/4/2009 3:31:50 PM">
  46:           <WelcomePageField id="038d1503-4629-40f6-adaf-b47d1ab2d4fe" />
  47:         </wpf:AllowedContentTypes>
  48:       </XmlDocument>
  49:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/defaultdocuments">
  50:         <dd:DefaultDocuments xmlns:dd="http://schemas.microsoft.com/office/documentsets/defaultdocuments" LastModified="11/5/2009 8:39:24 AM" AddSetName="True">
  51:           <DefaultDocument name="Enterprise Content Management.docx" idContentType="0x0101" />
  52:           <DefaultDocument name="Extending Search.docx" idContentType="0x0101" />
  53:         </dd:DefaultDocuments>
  54:       </XmlDocument>
  55:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  56:         <FormTemplates xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
  57:           <Display>DocSetDisplayForm</Display>
  58:           <Edit>ListForm</Edit>
  59:           <New>DocSetDisplayForm</New>
  60:         </FormTemplates>
  61:       </XmlDocument>
  62:       <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
  63:         <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
  64:           <New>_layouts/NewDocSet.aspx</New>
  65:         </FormUrls>
  66:       </XmlDocument>
  67:     </XmlDocuments>
  68:   </ContentType>
  69: </Elements>

As you can see, the basics are the same as for any content type. The main difference is in all the XmlDocument elements in there:

  • Some event handlers are hooked up to make sure the metadata gets pushed down into the child documents (plus some other stuff)
  • The content types that users are allowed to add to the set are specified
  • We specify which fields are shared between the documents the set contains
  • The fields that are shown on the welcome page are defined as well
  • We then specify if there’s default content to add when a new Document Set is created

After we’ve created the basic plumbing for the Document Set content type, we’ll need to make sure that the files that are required are created in the right place as well. In order to accomplish this we’ll add a SharePoint Module item to the solution. This module will create the welcome page and default content in the right location in the site collection. The element.xml file will contain the following content:

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
   3:   <Module Name="_ctsTest Doc Set_" HyperlinkBaseUrl="http://moss.contoso.com/sites/docsettest" Path="WelcomePages\Files\_cts\Test Doc Set" Url="_cts/Test Doc Set">
   4:     <File Url="docsethomepage.aspx" Path="docsethomepage.aspx">
   5:       <AllUsersWebPart WebPartOrder="0" WebPartZoneID="WebPartZone_TopLeft" ID="g_ae6da3d4_9233_45d6_b9fd_6300815e16c6">
   6:         <![CDATA[Content omitted]]>
   7:       </AllUsersWebPart>
   8:       <AllUsersWebPart WebPartOrder="0" WebPartZoneID="WebPartZone_CenterMain" ID="g_d8062545_cc87_4e82_9c55_cae80486ffea">
   9:         <![CDATA[Content omitted]]>
  10:       </AllUsersWebPart>
  11:       <AllUsersWebPart WebPartOrder="0" WebPartZoneID="WebPartZone_Top" ID="g_651be1ba_c8bb_4d29_87b0_87c769cd5179">
  12:         <![CDATA[Content omitted]]>
  13:       </AllUsersWebPart>
  14:     </File>
  15:     <File Path="Enterprise Content Management.docx" Url="Enterprise Content Management.docx" />
  16:     <File Path="Extending Search.docx" Url="Extending Search.docx" />
  17: </Module>
  18: </Elements>

We see that the page layout for the document set homepage is created in the _cts folder for the content type. The web parts that are placed on the page are configured here as well, so any modifications and additions will be used on the welcome page of all document sets based in this content type. Also the two documents for the default content are placed in the corresponding _cts folder in the site collection.

The final Visual Studio solution will look like this:

image

After deploying the solution and activating the feature, which is very easy to do with the new SharePoint stuff in Visual Studio (just press ctrl + f5), we can see that the _cts folder will be created in the site collection:

image

After we add the content type to a document library and create a new item based on the content type we’ll be presented with the following:

image

You can download the sample solution here: DocSetProvisioning.zip (62,88 KB) 
DISCLAIMER: This hasn't been properly tested, so there's is no guarantee it will work. If it f***s up your farm, the most you can expect as support from me, is an email wishing you good luck with restoring it.

Share:

Peter Gerritsen schreef

Comments (1)

Peter Gerritsen
Page 1 of 1 in the DocumentSets category

Zoeken

Categorie

Archief


Sign In