Monday 19 August 2013

Import Document set from XML

In my previous post I exported a data set to a file structure utilizing xml to store my meta data (Export document set) now I'm going to post a script to import that document set back into SharePoint, now i warn you this one is a bit quicker and dirtier then the previous, you're going to have tinker with it a bit for your list but it'll get you started.

<#
.Synopsis
   CCW Powershell Function to Restore Tenders Document Set
.DESCRIPTION
   Powershell functiont that itterates over a folder containing previously extracted tender document sets and restores them from an xml file that contains all required metadata
.EXAMPLE
   Example of how to use this cmdlet
#>
function Restore-ccwTenders
{
    [CmdletBinding()]
    Param
       (
        # the site url of your site collection ie http://wingtipserver
              [Parameter(Mandatory=$true,
                              HelpMessage="Enter in the site URL where the Tenders Documnet set resides")] 
              [ValidateScript({Get-SPSite -Identity $_ | Select-Object -Property Exists -ErrorAction SilentlyContinue})]
              [string]$SiteUrl,
              #The url of the tender document set
      [Parameter(Mandatory=$true,
                              HelpMessage = "Enter in the Display Name of the Tenders Document set")]
              [string]$DocumentSetName,
              #The Path on your local hardrive from which to restore the document set from
      [Parameter(Mandatory=$true,
                              HelpMessage = "Enter the file path where to Load your tenders from")]
              [ValidateScript({Test-Path $_})]
              [string]$ComputerPath
    )

    Begin
    {
              Clear-Host
              Add-PSSnapin "Microsoft.Sharepoint.PowerShell" -ErrorAction SilentlyContinue
             
              #get site using user supplied parameter
              $site = Get-SPSite($siteUrl)

              #get the Root web of the site
              $rootWeb = $site.RootWeb
    }
      
    Process
    {
              #Get the Tenders document set
              $DocumentSetList = $rootWeb.Lists.TryGetList($DocumentSetName)
             
              if($DocumentSetList -ne $null)
              {
                     #Get the conent type by name,
                     $cType = $DocumentSetList.ContentTypes["Tenders"]
                    
                     Get-ChildItem -Path $ComputerPath |
                     ForEach-Object {
                           $DocSet_HashTable = getTenderMetaData($_) as [System.Collections.Hashtable]
                           $newDocumentSet = [Microsoft.Office.DocumentManagement.DocumentSets.DocumentSet]::Create($tendersList.RootFolder,$_.name, $cType.Id, $DocSet_HashTable)  
                           uploadDocuments $rootWeb $_ $DocumentSetList.RootFolder
      
                           Write-Host "Created Document set: $_ " -foregroundcolor DarkGreen
                     }
              }
    }
      
    End
    {
              $rootWeb.Dispose()
              $site.Dispose()
    }
}

function getTenderMetaData($DocSetName)
{
       $xmlPath = $ComputerPath + "\" + $DocSetName + "\tender.xml"
       Write-Host $xmlPath
      
       if((Test-Path -Path $xmlPath) -eq $true)
       {
              $Metadata_HashTable = @{}
             
              Select-Xml -Path $xmlPath -XPath "/DS/Metadata/Data" |
              ForEach {
                     [string] $node = $_.Node | select -ExpandProperty Title
                     [string] $internalName = $_.Node | select -ExpandProperty InternalName
                     [string] $readOnly = $_.Node | select -ExpandProperty ReadOnly
                     [string] $value = $_.Node | % { $_.InnerText }
                     #Write-host ("Title={0},value={1}`n" -f $node, $value)
                    
                     if($readOnly -eq "False")
                     {
                           switch($node)
                           {
                                  "Title" {$Metadata_HashTable.Item("Title")=$value}
                                  "Description" {$Metadata_HashTable.Add("DocumentSetDescription", $value)}
                                  "Tender Category" {$Metadata_HashTable.Add("ccwTenderCategoryLookup", $value)}
                                  "Id Number" {$Metadata_HashTable.Add("ccwIdNumber", $value)}
                                  "Request Type" {$Metadata_HashTable.Add("ccwRequestType", $value)}
                                  "Start Time" {$Metadata_HashTable.Add("ccwTenderStartTime", [System.DateTime]$value)}
                                  "End Time" {$Metadata_HashTable.Add("ccwTenderEndTime", [System.DateTime]$value)}
                                  "Extension" {$Metadata_HashTable.Add("ccwTenderExtensionTime", [System.DateTime]$value)}
                                  default {$Metadata_HashTable.Add($internalName, $value)}
                           }
                     }
              }
      
              return $Metadata_HashTable
       }
}

function uploadDocuments($web, $DocSetName, $DocSetRootFolder)
{
       $xmlPath = $ComputerPath + "\" + $DocSetName + "\tender.xml"
       Write-Host $xmlPath woot  -ForegroundColor DarkCyan
       if((Test-Path -Path $xmlPath) -eq $true)
       {
              Select-Xml -Path $xmlPath -XPath "/DS/Files/File" |
              ForEach {
                     $file_HashTable = @{}
             
                     $ContentTypeName = $_.Node | select -ExpandProperty ContentType
                     $SortOrder = $_.Node | select -ExpandProperty SortOrder
                     $relativeFilePath = $_.Node | select -ExpandProperty FilePath
                     $AttachmentURLPath = $_.Node | select -ExpandProperty urlPath
                    
                     $AttachmentFilePath = [system.IO.path]::Combine($ComputerPath , $relativeFilePath)
                     write-host $AttachmentFilePath   
                     #Write-Host ("Content type = `"{0}`"`nSort Order = `"{1}`"`nFile Path = `"{2}`"`nUrl Path = `"{3}`"" -f $ContentTypeName, $SortOrder, $AttachmentFilePath, $AttachmentURLPath) -ForegroundColor DarkBlue
                    
                     switch($ContentTypeName)
                     {
                           "Addendum" {
                                  $file_HashTable.add("ContentTypeId", "0x0101001cf9a0ea451d4c49971bce57ae51e3df001bea931548e949eeadeb7945c74f41b2")
                                  $file_HashTable.add("ContentType", "Tender Addendum")
                                  $file_HashTable.add("ccwTenderAddendumSortOrder", $SortOrder)
                           }
                           "Request Document"{
                                  $file_HashTable.add("ContentTypeId", "0x0101001CF9A0EA451D4C49971BCE57AE51E3DF")
                                  $file_HashTable.add("ContentType", "Tender Request Document")
                           }
                           "Unofficial Results"{
                                  $file_HashTable.add("ContentTypeId", "0x0101001cf9a0ea451d4c49971bce57ae51e3df00e608217df15942e389ca1810df08f8dc")
                                  $file_HashTable.add("ContentType", "Tender Unofficial Results")
                           }
                     }
             
                     #Create instance of Folder
                     $spFolder = $web.GetFolder($DocSetRootFolder)
                     Write-Host $AttachmentFilePath -ForegroundColor Magenta
                     $file = Get-Item $AttachmentFilePath
                    
                     $fileStream=([System.IO.FileInfo](Get-Item $file.FullName)).OpenRead()
                     $spfile = $spFolder.Files.Add("Lists" + $AttachmentURLPath, [System.IO.Stream]$fileStream, $file_HashTable, $true)
                     $fileStream.Close()
                    
              }
       }

}

Export document set to XML

This script pulls a document set out of SharePoint and saves it to your hard drive.

#load SharePoint Powershell snap in
Add-PSSnapin "Microsoft.Sharepoint.PowerShell" -ErrorAction SilentlyContinue

<#
.Synopsis
   Save document set to hard drive
.DESCRIPTION
      Iterates through each tender in document set and procededs to save them to the local hard drive.
.EXAMPLE
   retrieve-ccwTenders -siteUrl http://wingtipserver -listName MyDocumentSet -savePath c:\
#>               
function retrieve-ccwTenders
{
    [CmdletBinding()]
      param(
            #Site url for the sharepoint collection
            [Parameter(Mandatory=$true,
                           HelpMessage="Enter in the site URL where the Tenders Documnet set resides")]
            [ValidateScript({Get-SPSite -Identity $_ | Select-Object -Property Exists -ErrorAction SilentlyContinue})]
            [string]$siteUrl,
            #The name of the documents set
            [Parameter(mandatory=$true,
                           HelpMessage = "Enter in the Display Name of the Document set")]
            [string]$listName 
            #The path where to save your Tenders
            [Parameter(Mandatory=$true,
             HelpMessage = "Enter the file path where to save your tenders document set")]
            [ValidateScript({Test-Path $_})]
            [string]$SavePath
      )

    Begin
    {
            Clear-Host
           
            #get site using user supplied parameter
            $site = Get-SPSite($siteUrl)

            #get the Root web of the site
            $rootWeb = $site.RootWeb
    }
   
      Process
    {
            #get Documnet Set instance
            $DocumentSet = $rootWeb.Lists.TryGetList($listName)
     
            #make sure the document set is not null
            if($DocumentSet -ne $null)
            {
                  #iterate through all documents sets(tenders)
                  $DocumentSet.Items | foreach {
                        #ensure that item is a document set
                        if($_["HTML File Type"] -eq "SharePoint.DocumentSet")
                        {
                              SaveDocSetMetadata $_
                        }
                        elseif($_["HTML File Type"] -eq $null)
                        {
                              #save the document to folder & Append File metadata to XML Document
                              SaveDocSetDocument $_
                        }
                  }
            }
    }
   
      End
    {
            $rootWeb.Dispose()
            $site.Dispose()
    }
}

function SaveDocSetMetadata($docset)
{
      $DocsetSavePath = [System.IO.Path]::Combine("$savePath\DocumentSet", $docset.Title)
           
      #create folder on HD to store Tender Data
      if((Test-Path $DocsetSavePath) -eq $false)
      {
            New-Item -ItemType directory -Path $DocsetSavePath | Out-Null
      }
                             
      #create xml object in memory
      $docsetXML = New-Object Xml
                             
      #create xml declaration
      [System.Xml.XmlDeclaration] $xmlDeclaration = $docsetXML.CreateXmlDeclaration("1.0", "UTF-16", $null);
      $docsetXML.AppendChild($xmlDeclaration)  | Out-Null
                             
      #create Root Node
      $root = $docsetXML.CreateElement("DS")   
      $docsetXML.AppendChild($root) | Out-Null
           
      #create metadata node
      $metadata = $docsetXML.CreateElement("Metadata")
      $root.AppendChild($metadata)  | Out-Null
     
      #get relevent metaData for tender
      $docset.Fields | foreach {   
            $data = $docsetXML.CreateElement("Data")
           
            $data.InnerText = $docset[$_.Title]
            $data.SetAttribute("Title", $_.Title)
            $data.SetAttribute("InternalName", $_.InternalName)
            $data.SetAttribute("ReadOnly", $_.ReadOnlyField)
           
            $metadata.AppendChild($data)  | Out-Null 
      }
           
      #save xml object to file
      $temp = $docsetXML.Save("$DocsetSavePath\Tender.xml")
     
      Write-output "Created $DocsetSavePath/Tender.xml"
}

function SaveDocSetDocument($docset)
{
      $wc = New-Object System.Net.WebClient
     
      $source = $docset["Encoded Absolute URL"]
      $folder = $docset["Path"].Substring($docset["Path"].lastindexof("/")+1)
      $fileName = $docset["FileLeafRef"]
     
      $destination = [System.IO.Path]::Combine("$savePath\DocumentSet", $folder)
                 
      Try
      {
            $wc.DownloadFile($source, [System.IO.Path]::Combine($destination, $fileName))
      }
      Finally
      {
            $wc.Dispose()
      }

      #Get the xml File path
      $xmlPath = [System.IO.Path]::Combine($destination, "Tender.xml")
                       
      #get the xml document
      [xml]$docsetXML = Get-Content -Path $xmlPath
     
      #get the last element in the xml document
      $lastChild = $docsetXML.DS.get_LastChild()
           
      #check if the last element is <files />, create one if it isn't
      if($lastChild.Name -eq "Files")
      {
            $files = $lastChild
      }
      else
      {
            $files = $docsetXML.CreateElement("Files")
      }
           
      #grab the <files /> element
      $filesNode = $docsetXML.DS.AppendChild($files)
                       
      #create a <file /> element         
      $file = $docsetXML.CreateElement("File")

      $file.SetAttribute("ContentType", $docset["Content Type"])
      $file.SetAttribute("SortOrder", $docset["Sort Order"])
      $file.SetAttribute("FilePath"$folder + "\" + $fileName)
      $file.SetAttribute("urlPath", $docset["Server Relative URL"])
           
      #append the <file /> element to the <files /> element
      $file = $filesNode.AppendChild($file)  | Out-Null
           
      #save xml changes
      $docsetXML.Save($xmlPath)

}