Accessing SharePoint Online Document Libraries with Unattended Scripts
Here at SPR we’ve helped a lot of our clients leverage the tools made available in SharePoint Online. I recently ran into a challenge with SharePoint Online that was interesting enough to blog about. A client had just migrated the majority of their documents to SharePoint Online. Getting the users access was a breeze using WebDAV mapped drives. The client asked us to get one of their servers connected to the same Document Library so they could automate content distribution.
A mapped drive on the server like we setup for the users was out because these were unattended scripts. I also didn’t think the reliability of WebDav was good enough. All of my research was ending at the same dead end, getting access. Each option ultimately required a user to enter the credentials at runtime. I finally ran across SPFileZilla. SPFileZilla is an application that connects to SharePoint just like FileZilla would connect to an FTP site. The key was that SPFileZilla accepted the username and password instead of opening the Office365 Portal. Every other method of connecting involved a user logging into the Office365 Portal. Once that was done the script would use the resulting token to get access. The fact that SPFileZilla didn’t require the token gave me hope! And wouldn’t you know it SPFileZilla is open source! I began reverse engineering the code to see exactly how this process worked.
Now that I’ve covered most of the backstory lets get into how it works….
There are three main things we need to know before using the script.
- Local Path (the files we’re sending)
- The credentials used to access the site.
- The Document Library (and path) that will receive these files.
Providing the local path is pretty simple so I’ll jump right to the credentials. The tools that makes this script possible are the SharePoint Client Components (http://www.microsoft.com/en-us/download/details.aspx?id=35585). These tools need to be installed before using the script.
There are two ways to get the credentials saved for the script. I HIGHLY recommend the first due to the much higher security. The second requires the password to be saved in the script. There may be times when this is required. In those instances, make sure to setup a service account with only access to the absolutely necessary resources for the script to work.
Prompting for the user and password at runtime. $User = Read-Host -Prompt “Please enter your username”
[code]$Password = Read-Host -Prompt "Please enter your password" -AsSecureString[/code]
Saving the credentials in the script or a config file. For simplicity I’ll show how they’re saved in the script.
[code]$User = "UsernameGoesHere" $Password = ConvertTo-SecureString -String "PasswordGoesHere" -AsPlainText -Force
[/code]
The last piece of information left to provide is the destination. The site, document library, and directory are all separate variables.
[code]$SiteURL = "https://SiteNameHere.sharepoint.com" $DocLibName = "Document Lib Here" $Directory = "Archived Documents"
[/code]
Now that the script has the info that it needs lets walk through the logic.
Since the tools are .Net classes, we need to add them so we can use them in Powershell.
[code]Add-Type -Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions15ISAPIMicrosoft.SharePoint.Client.dll"
Add-Type -Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions15ISAPIMicrosoft.SharePoint.Client.Runtime.dll"[/code]
Then apply the credintials to the site.
[code]$Context = New-Object Microsoft.SharePoint.Client.ClientContext($Site) $Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User,$Password) $Context.Credentials = $Credentials
[/code]
Go and get the list from the site.
[code]$List = $Context.Web.Lists.GetByTitle($DocLib) $Context.Load($List) $Context.ExecuteQuery()
[/code]
And finally upload each file in the local folder.
[code class=”brush: Powershell”]Foreach ($File in (dir $Folder -File))
{
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $Directory + $File
$Upload = $List.RootFolder.Files.Add($FileCreationInfo)
$Context.Load($Upload)
$Context.ExecuteQuery()
}
[/code]
And that’s it! Very simple but can be really helpful. This script allowed our client to use their integration tool with their SharePoint Document Library. The integration tool could only publish to UNC locations so this script was used to bridge the gap. Here’s the script in it’s entirety.
[code]#Collect local folder, credentials, and destination
$User = "UsernameGoesHere"
$Site = "<a href="https://sitenamegoeshere.sharepoint.com/">https://SiteNameGoesHere.sharepoint.com</a>"
$Folder = "C:FilesToUpload"
$DocLib = "Document Lib Here"
$Directory = "Archived Documents"
$User = Read-Host -Prompt "Please enter your username"
$Password = Read-Host -Prompt "Please enter your password" -AsSecureString
#Only use this if absolutely necessary
#$Password = ConvertTo-SecureString -String "PasswordGoesHere" -AsPlainText -Force
#Apply the credentials to the site using the SharePoint Client Components
Add-Type -Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions15ISAPIMicrosoft.SharePoint.Client.dll"
Add-Type -Path "C:Program FilesCommon FilesMicrosoft SharedWeb Server Extensions15ISAPIMicrosoft.SharePoint.Client.Runtime.dll"
$Context = New-Object Microsoft.SharePoint.Client.ClientContext($Site)
$Credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($User,$Password)
$Context.Credentials = $Credentials
#Retrieve list from site
$List = $Context.Web.Lists.GetByTitle($DocLib)
$Context.Load($List)
$Context.ExecuteQuery()
#Upload each file
Foreach ($File in (dir $Folder -File))
{
$FileStream = New-Object IO.FileStream($File.FullName,[System.IO.FileMode]::Open)
$FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
$FileCreationInfo.Overwrite = $true
$FileCreationInfo.ContentStream = $FileStream
$FileCreationInfo.URL = $Directory + $File
$Upload = $List.RootFolder.Files.Add($FileCreationInfo)
$Context.Load($Upload)
$Context.ExecuteQuery()
}[/code]