The Delegate.SPOcopy library can be installed from NuGet:
PM> Install-Package Delegate.SPOcopy

What is it?

Delegate SharePoint Online copy (Delegate.SPOcopy) is a library that copies a local folder, including files and subfolders (recursively), to SharePoint Online, ensuring valid SharePoint relative url names.



open System
open Delegate
open Delegate.SPOcopy

let domain = @"sharepointonlinecopy"
let usr = sprintf @"" domain
let pwd = @"pass@word1"
let source = @"D:\tmp\spo-copy"
let host = Uri( sprintf @"" domain)
let target = Uri(host.ToString() + @"Shared%20Documents")
let o365 = 
    Office365.getCookieContainer host usr pwd,

copy source target usr pwd LogLevel.Info

Evaluates to the following output when called as:

fsianycpu Delegate.SPOcopy.Sample.fsx > Delegate.SPOcopy.Output.txt 2> Delegate.SPOcopy.Error.txt


2016-02-03T08:08:01.5752722+01:00 - Info: "SharePoint Online copy (SPOcopy) - Started"
2016-02-03T10:12:27.6846710+01:00 - Info: "SharePoint Online copy (SPOcopy) - Finished"


Remark: As we can see, the 33.198 files and 1.630 folders (1 GB) are created in about two hours on the SharePoint Online instance, with no errors whatsoever

How it works and limitations

  • A few words on how the Delegate.SPOcopy library works:
    • In order to be able to upload the files with the mminimal amount of noise we rely on using SharePoint Onlines REST service instead of their SOAP, see Martin Lawrence REST vs SOAP for more info. This allows us to use F# powerfull but simple async engine to implement parallelism.
    • For more information, please look into the code (about +275 lines) at GitHub

  • We describe a few limitations we found while we were making the library:
    • Only works with Office365 account without ADFS: As we have borrowed Ronnie Holms Office365 module, we haven't expanded it so it also would supports ADFS users as we think the easiest approach is that the Office365 Admin just creates a new service account in the cloud without synchronization with the local AD.
    • No executable: The reason we haven't created an executable file is that we then have to rely on .bat or .cmd file in order to execute the application with command-line arguments. We think that the approach of creating a type-safe F# script file is a much better approach.

Contributing and copyleft

The project is hosted on GitHub where you can report issues, fork the project and submit pull requests.

The library is available under an Open Source MIT license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.

namespace System
type Delegate =
  member Clone : unit -> obj
  member DynamicInvoke : params args:obj[] -> obj
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member GetInvocationList : unit -> Delegate[]
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Method : MethodInfo
  member Target : obj
  static member Combine : params delegates:Delegate[] -> Delegate + 1 overload
  static member CreateDelegate : type:Type * method:MethodInfo -> Delegate + 9 overloads

Full name: System.Delegate
module SPOcopy

from Delegate
val domain : string

Full name: Index.domain
val usr : string

Full name: Index.usr
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val pwd : string

Full name: Index.pwd
val source : string

Full name: Index.source
val host : Uri

Full name:
Multiple items
type Uri =
  new : uriString:string -> Uri + 5 overloads
  member AbsolutePath : string
  member AbsoluteUri : string
  member Authority : string
  member DnsSafeHost : string
  member Equals : comparand:obj -> bool
  member Fragment : string
  member GetComponents : components:UriComponents * format:UriFormat -> string
  member GetHashCode : unit -> int
  member GetLeftPart : part:UriPartial -> string

Full name: System.Uri

Uri(uriString: string) : unit
Uri(uriString: string, uriKind: UriKind) : unit
Uri(baseUri: Uri, relativeUri: string) : unit
Uri(baseUri: Uri, relativeUri: Uri) : unit
val target : Uri

Full name:
Uri.ToString() : string
val o365 : Net.CookieContainer * string

Full name: Index.o365
module Office365

from Delegate
val copy : local:string -> url:Uri -> usr:string -> pwd:string -> loglvl:LogLevel -> unit

Full name: Delegate.SPOcopy.copy
type LogLevel =
  | Info = 5
  | Warning = 6
  | Error = 4
  | Verbose = 7

Full name: Delegate.SPOcopy.Logger.LogLevel
LogLevel.Info: LogLevel = 5