For a while ago I needed to copy all files from a document library within a SharePoint 2007 site to the hard drive. So I didn’t need to copy files from SharePoint to SharePoint so I couldn’t use the stsadm -o export command or Chris O’Brien’s nice SharePoint Content Deployment Wizard. I came across the SPIEFolder application which should work with SharePoint 2007 and 2010. It has a site on codeplex: spiefolder.codeplex.com, but neither the binary nor the source code can be downloaded from there. After some searching I found the binary in the author’s skydrive. The fact that the source code was not available seemed as an disanvantage because I could not know what code was run. Nevertheless I tried it out and it didn’t work:
spiefolder -o export -url "http://dev/Documents" -directory c:\tolle\Documents –recursive
I got the following error:
The Web application at http://dev/Documents could not be found. Verify that you have typed the URL correctly. If the URL should be serving existing content, the system administrator may need to add a new request URL mapping to the intended application.
So I wrote my own code to copy the documents. To write a console application feels so yesterdayish, so it is written in PowerShell. Even if there are no PowerShell snapins for SharePoint 2007, you have access to the entire Server Object Model, the only thing you have to do is to load the SharePoint assembly:
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
Then you can instantiate all SharePoint objects like in C#, but in a PowerShell way:
$site = new-Object Microsoft.SharePoint.SPSite("http://dev")
$web = $site.OpenWeb()
You can even download a module for emulating cmdlets: Get-SPWeb, Get-SPWebApplication and Get-SPFarm, written by Natalia Tsymbalenko (sharing-the-experience.blogspot.com) to get started or just to find some inspiration.
I have created a ps1-script which only does one thing – it copies an entire document library to disk. Much of inspiration to structure the script comes from “Delete-SPListItems” (sharepointryan.com).
Here it is: Pull-Documents.ps1
<#
.Synopsis
Use Pull-Documents to copy the entire document library to disk
.Description
This script iterates recursively over all directories and files in a document library and writes binary data to the disk
The structure is kept as in the Document library
It is mainly written for SharePoint 2007, but it works even in SharePoint 2010
.Example
Pull-Document -Url http://dev -Library "Shared Documents"
.Notes
Name: Pull-Documents.ps1
Author: Anatoly Mironov
Last Edit: 2012-12-03
Keywords: SPList, Documents, Files, SPDocumentLibrary
.Links
https://sharepointkunskap.wordpress.com
http://www.bool.se
.Inputs
None
.Outputs
None
#Requires -Version 1.0
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)][System.String]$Url = $(Read-Host -prompt "Web Url"),
[Parameter(Mandatory=$true)][System.String]$Library = $(Read-Host -prompt "Document Library")
)
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")
$site = new-object microsoft.sharepoint.spsite($Url)
$web = $site.OpenWeb()
$site.Dispose()
$folder = $web.GetFolder($Library)
$folder # must output it otherwise "doesn't exist" in 2007
if(!$folder.Exists){
Write-Error "The document library cannot be found"
$web.Dispose()
return
}
$directory = $pwd.Path
$rootDirectory = Join-Path $pwd $folder.Name
if (Test-Path $rootDirectory) {
Write-Error "The folder $Library in the current directory already exists, please remove it"
$web.Dispose()
return
}
#progress variables
$global:counter = 0
$global:total = 0
#recursively count all files to pull
function count($folder) {
if ($folder.Name -ne "Forms") {
$global:total += $folder.Files.Count
$folder.SubFolders | Foreach { count $_ }
}
}
write "counting files, please wait..."
count $folder
write "files count $global:total"
function progress($path) {
$global:counter++
$percent = $global:counter / $global:total * 100
write-progress -activity "Pulling documents from $Library" -status $path -PercentComplete $percent
}
#Write file to disk
function Save ($file, $directory) {
$data = $file.OpenBinary()
$path = Join-Path $directory $file.Name
progress $path
[System.IO.File]::WriteAllBytes($path, $data)
}
#Forms folder doesn't need to be copied
$formsDirectory = Join-Path $rootDirectory "Forms"
function Pull($folder, [string]$directory) {
$directory = Join-Path $directory $folder.Name
if ($directory -eq $formsDirectory) {
return
}
mkdir $directory | out-null
$folder.Files | Foreach { Save $_ $directory }
$folder.Subfolders | Foreach { Pull $_ $directory }
}
Write "Copying files recursively"
Pull $folder $directory
$web.Dispose()
I have tested this script in SharePoint 2007 and 2010. It works. Let me know if you find this useful or have some suggestions.
Add Comments column to your sharepoint list
If you have used Issue tracking list template in SharePoint you must have marked that the comments are added and marked with author name and datetime. It is handy to have these micro “discussion boards” on items. The comment-formed communication can help to fine-tune task definitions. By the way, have you seen Trello?
So the question is how we can create this column in other lists? Here is a little tutorial how to create “append-only comments”, as they are called:
Go to your list and enable versioning
Add “Append-only comments” column from existing site columns
(In Swedish this Site Column is called: “Lägg endast till kommentarer”)
Go ahead and write comments
Add append-only comments in XML