Moving a DocumentSet through code – pt1

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.

Leave a Reply