Download SharePoint Online Files using MAC CURL Command

Problem Statement
MAC SharePoint users were downloading the files from SharePoint 2007 Document Libraries using the CURL command but the same is not working after migrating the SharePoint 2007 sites to SharePoint Online(SPOL).

curl -k --NTLM --user "domain\user":"password" -o

SharePoint Online uses claims based authentication and direct NTLM based curl commands are not allowed.

SPOL allows remote applications to call the REST API with user impersonation. This article demonstrates how to access SPOL REST API and download the files from a tenant using Apple Bash Script and Curl commands. However, outside of .NET the authentication piece is not so straightforward. App authentication solves this issue for registered apps but in this document you will see how remote user authentication can be achieved, regardless of platform.

The below diagram illustrates the HTTP requests which need to be made in order to authenticate SharePoint Online.


Applies To
Office 365 Tenant connected with Active Directory Federated Service(ADFS) and MAC OS

Execution Steps

  • Download the file from here
  • Open file in a text editor(TextWrangler/TextMate) and update the UserName (Line #4) and Password (Line #5).


Note: The UserName & Password provided should have access to download the file from SharePoint Online.

  • To download the file from a different SharePoint Online site/library/folder/file where the account has access, change the values of EndPoint(Line #6) and FileServerRelativeUrl(Line #7) values.
  • Save the file
  • Open Terminal (command line tool) and go to the path where file is saved
  • Execute the following command to convert the file executable chmod 700
  • Run the script using just the name of the script(Example : ./
  • If all goes well, you should be able to see the downloaded file in the output path given in OutputFilePath(Line #9).

Failure Chances

  • UserName and Password provided might be wrong
  • Access denied from SharePoint Online for the UserName and Password provided
  • Provided Site/Document Library/Folder/File is not available in SharePoint Online or wrong
  • Text Editor might have changed or corrupted the file while saving

ASP.NET Custom Web API & Curl Bash and PowerShell commands to download files from SharePoint Online

In this article I am going to illustrate how to download a file from SharePoint Online using Custom ASP.NET Web API and Curl Bash Command.

Model Definition

using System.ComponentModel.DataAnnotations;
using SPOL.FileDownload.Filters;

namespace SPOL.FileDownload.Models
public class SPOLFile
[Required(ErrorMessage = “Site Url is not passed with the endpoint”)]
[Display(Name = “SiteUrl”)]
public string SiteUrl { get; set; }

[Required(ErrorMessage = “Library Name is not passed with the endpoint”)]
[Display(Name = “LibraryName”)]
public string LibraryName { get; set; }

[Display(Name = “FolderPath”)]
public string FolderPath { get; set; }

[Required(ErrorMessage = “File Name is not passed with the endpoint”)]
[Display(Name = “FileName”)]
public string FileName { get; set; }

Model Validation

using System.Net;
using System.Net.Http;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;

namespace SPOL.FileDownload.Filters
public class ValidateSPOSiteModelAttribute : ActionFilterAttribute
public override void OnActionExecuting(HttpActionContext actionContext)
if (actionContext.ModelState.IsValid == false)
actionContext.Response = actionContext.Request.CreateErrorResponse(
HttpStatusCode.BadRequest, actionContext.ModelState);

Model Field Validation

using System.ComponentModel.DataAnnotations;
using SPOL.FileDownload.Helpers;
using Microsoft.SharePoint.Client;

namespace SPOL.FileDownload.Filters
public class ValidateSiteAttribute : ValidationAttribute
public override bool IsValid(object value)
ClientContext clientContext = null;
var url = value as string;

if (string.IsNullOrEmpty(url))
return false;

clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(url, Settings.serviceAccountUserId, Settings.serviceAccountPassword);
var web = clientContext.Web;

return true;
ErrorMessage = “Site url you have passed in not valid.”;
return false;
if (clientContext != null)
ErrorMessage = “There is a problem accessing the site url.”;
return false;


Model Field Validation with Validation Context to pass parameters

using System.ComponentModel.DataAnnotations;
using SPOL.FileDownload.Helpers;
using Microsoft.SharePoint.Client;
using System;
using System.Reflection;
using System.IO;

namespace SPOL.FileDownload.Filters
public class ValidateFileAttribute : ValidationAttribute
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
bool isValid = true;
string ErrorMessage = "";
ClientContext clientContext = null;


var filename = value as string;

object instance = validationContext.ObjectInstance;
Type type = instance.GetType();

PropertyInfo propertySiteUrl = type.GetProperty("SiteUrl");
PropertyInfo propertyLibraryName = type.GetProperty("LibraryName");
PropertyInfo propertyFolderPath = type.GetProperty("FolderPath");

object siteUrl = propertySiteUrl.GetValue(instance);
object libraryName = propertyLibraryName.GetValue(instance);
object objFolderPath = propertyFolderPath.GetValue(instance);

string folderpath = Convert.ToString(string.IsNullOrEmpty((string)objFolderPath) ? "" : objFolderPath);

if (string.IsNullOrEmpty(filename))
isValid = false;
ErrorMessage = "File name is not passed with the endpoint";

string extention = Path.GetExtension(filename);

if (string.IsNullOrEmpty(extention))
ErrorMessage = "Not a valid file name extention.";
isValid = false;

clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(siteUrl.ToString(), Settings.serviceAccountUserId, Settings.serviceAccountPassword);

var url = new Uri(siteUrl.ToString());
var relativeUrl = String.Format("{0}/{1}/{2}/{3}", url.AbsolutePath, libraryName.ToString(), folderpath, filename);

var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, relativeUrl);
isValid = true;
ErrorMessage = "File name you have passed in not avilable.";
isValid = false;
if (clientContext != null)
ErrorMessage = "There is a problem accessing the file.";
isValid = false;

if (isValid)
return ValidationResult.Success;
return new ValidationResult(ErrorMessage);


using SPOL.FileDownload.Filters;
using SPOL.FileDownload.Helpers;
using SPOL.FileDownload.Models;
using Microsoft.SharePoint.Client;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;

namespace SPOL.FileDownload.Controllers
public class DownloadFileController : ApiController
public HttpResponseMessage DownloadFile([FromUri] SPOLFile spolFile)
MemoryStream stream = new MemoryStream();
ClientContext clientContext = null;

if (ModelState.IsValid)
clientContext = new OfficeDevPnP.Core.AuthenticationManager().GetSharePointOnlineAuthenticatedContextTenant(spolFile.SiteUrl, Settings.serviceAccountUserId, Settings.serviceAccountPassword);

var url = new Uri(spolFile.SiteUrl);
var relativeUrl = String.Format(“{0}/{1}/{2}/{3}”, url.AbsolutePath, spolFile.LibraryName, spolFile.FolderPath, spolFile.FileName);

var fileInfo = Microsoft.SharePoint.Client.File.OpenBinaryDirect(clientContext, relativeUrl);

var buf = new byte[1024 * 16];
int byteSize;

while ((byteSize = fileInfo.Stream.Read(buf, 0, buf.Length)) > 0)
stream.Write(buf, 0, byteSize);

string mediaType = MimeMapping.GetMimeMapping(spolFile.FileName);

var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(stream.ToArray());
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue(“attachment”);
result.Content.Headers.ContentDisposition.FileName = spolFile.FileName;
result.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType);

return result;
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
catch (Exception ex)
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.ToString()); // new HttpResponseMessage(HttpStatusCode.InternalServerError);
if (stream != null)
if (clientContext != null)



Bash Command

libraryname='Files to Download'
folderpath='First Level/Second Level'


curl “${url}” -o “${filename}”
PowerShell Command
The same operation can be done in windows OS using PowerShell commands as well.

Invoke-RestMethod -Uri " to Download&folderpath=&filename=Azure_Application_Insights.pptx" -Method Get | Out-File -filepath "C:\Users\joseph\Downloads\Azure_Application_Insights.pptx"

KPI Indicators using SharePoint JavaScript Display Templates & Bootstrap

SharePoint users can reference a JavaScript files and use the same as settings to Control the rendering of fields, row items, list forms. In this article i will show you how we can display KPI indicator using a JavaScript file.


  • Create a custom list with the following columns
Column Name Filed Type
Title Single line of text
Status Choice


The values are





  • Add some items to the newly created list with different Status values
  • Upload the Task_Status_Indicator.js file under Site Settings –> Web Designer Galleries –> Master pages and page layouts and update the following properties


  • Publish Task_Status_Indicator.js file as major Version
  • Upload your own images for indicators with the following names





Note: I have uploaded my images in the Site Assets library. If you wish to change the image names or location where it is uploaded, change the img tag references in Task_Status_Indicator.js and upload again.

  • Go to List URL/AllItems.aspx and edit the List View webpart and add the javascript display template file path as shown below


Note: In my case it will be ~site/_catalogs/masterpage/Task_Status_Indicator.js

  • Click OK/Apply to see the changes as shown below


With pagination 



Change the logic in JS file as per your requirement and design.

Pagination is also implemented in this approach.

Basic Site Provisioning using SharePoint Framework client-side web part and Microsoft Bot Framework


Sample SharePoint Framework client-side web part illustrating Site Provisioning using Microsoft Bot Framework.



Applies to


Solution Author(s)
js-bot-framework Joseph Velliah (SPRIDER, @sprider)

Version history

Version Date Comments
1.0 December 13, 2016 Initial release



Minimal Path to Awesome

  • clone this repo from here

Register Bot

  • go to and sign in with your Microsoft account
  • click on Register a bot link at the top botregister-step1.png
  • fill all the details like Name, Bot handle, Description and Messaging endpoint
  • generate a new App ID and password by clicking Create Microsoft App ID and password button. Save this value somewhere as we will use in this next step
  • accept the terms and click Register
  • your bot is now registered
  • click edit link under Web Chat channel and notedown the Secret key to configure the client web part botregister-step3
  • you can test your connection here by typing hello message and click Send. Try this step after completing “Publish Bot in Azure Web App” step

Publish Bot in Azure Web App

  • in the Azure Management Portal at create a new Web App(example:
  • download the publishing profile from the web app we just created. This will be used to publish the Bot in Azure using Visual Studio
  • Open the web.config file in AskSPRider.sln and update the MicrosoftAppId, MicrosoftAppPassword, O365AdminId and O365AdminPassword
    • MicrosoftAppId – App ID generated from Bot Registration Process
    • MicrosoftAppPassword – App Secret generated from Bot Registration Process
    • O365AdminId – SharePoint Online Admin User Id(example:
    • O365AdminPassword – SharePoint Online Admin Password
  • save the web.config file
  • right click on the project and publish the bot in Azure using the publishing profile downloaded

Configure web part

  • go to the working directory to the webpart folder in the command line run:
    • npm i
    • tsd install
    • gulp serve
  • add Ask SP Rider webpart and edit it
    • configure bot name and web chat secret key botregister-step4
    • type hello and proceed with site creation process
    • final output botregister-step4


This project illustrates the following concepts:

  • connecting SharePoint Framework client-side web part to a custom bot
  • showing how to embed bot within client-side web part
  • how to create a sub-site by posting set of questions to the user via bot
  • bot form field validations

WebParts in Tabs & Accordions where Tabs Act as Accordions in Lower Resolutions


The purpose of this document is to highlight conversion of several WebParts added in a page to tabs which act as accordions in lower resolutions.


Convert all WebParts in a zone to TABS

  • Default Order
  • Specific Order

Establish responsive behavior of TABS i.e. Tabs to act as accordions in lower resolutions

Implement CA theme and allow for theme customization.

Multi-browser support

Insights on Code

To convert web parts to tabs layout

To establish interactions on tab, conversion to accordion in lower resolutions

  • Custom code


  • JQuery library

Tested On

  • Chrome (Latest)
  • Firefox (Latest)
  • Internet Explorer 11


Download the code from Github


Pre-requisite – if files are not on CDN:

Upload the below files in the site-specific documents library that you are currently working and capture its absolute URL path

  • jquery-1.11.1.min.js
  • custom-tabs.js
  • custom-tabs.css
  • tabs.js

Pre-requisite – if CDN dependencies are on CDN

Upload the below files in the site-specific documents library that you are currently working and capture its absolute URL path

  • tab.js

Creating Default Tab Order

CREATE a web part page

new page.PNG

ADD required WebParts into desired zones.


For instance, we’ve added

  • Page Viewer Web part
  • Image Viewer Web part

After adding the required web parts, add a content editor web part


EDIT the content editor web part and paste tabs.js URL inside the Content Link box

cewp tab config.PNG

Click OK. You’d see that all web parts will now be converted into TABS

Stop Editing to preview the page. The page would look as below

new tabs.PNG

To check Responsivity, resize your browser. Tabs Would Render as Accordions


Note: Tabs layout turns into Accordion layout below 992 pixels

The above illustrates the default behavior of the Tabs. All web parts would become tabs in a random order.

Creating Specific Tab Order

To create a specific tab order,

Edit tabs.js file in notepad

Add two forward slashes (//) before genWebpartTabs(); function as shown below

comment genWebpartTabs.png

Find “//Put 2 web parts in 2 different tabs” uncomment i.e. removed forward slashes as shown below

add titles genWebpartTabs.png
webPartTitles is an array of web part titles. As shown in the above snapshot, write the tiles of your WebParts using the following rules

  • Web part titles to be enclosed in double quotes or single quotes
  • Each web part title must be comma separated
  • The last web part title must not end with a comma after the quote

For instance, in the Default Tab Order (Previous section), we’ve created web parts in a random order. Currently the order is as below:

  1. Page Viewer
  2. Image Viewer

If you’d like to change this to

  1. Image Viewer
  2. Page viewer

Then update the script as below and save the file.
//Put 2 web parts in 2 different tabs
var webPartTitles = [“Image Viewer”,”Page Viwer”];

Upload the file to your site’s document library and capture its absolute URL path.

Follow steps 3 to 5 as illustrated in Default Tab Order section and you’d see the tab order being changed as specified in the above mentioned snippet.


Customization – Appearance

tabs.js file allows you to customize the appearance of the of the tabs which includes

  • Active Tab Color
  • Active Tab Text Color
  • Inactive Tab Color
  • Inactive Tab Text Color
  • Inactive Tab Color On Mouse Hover
  • Tab Content Background Color

These parameters are available in appearance_config object inside tabs.js file as shown below:

default color config.png

To change the appearance of the tabs, change the values inside the quotes of this object. You can also use common color names such as red, blue etc. but it is recommended to use a HEX value only.

For instance, we’d like to see

  • Active tab color as Light Blue i.e. #53bbD4
  • Active tab text color as white i.e. #FFFFFF
  • Inactive tab color as Dark Blue i.e. #22465E
  • Inactive tab text color as Middle Grey i.e. #91838B
  • Inactive tab hover color as Dark Blue i.e. #22465E
  • Tab content background color as Warm Grey i.e. #D8D8D8

To do so, update the appearance_config as below

Save and Upload the tabs.js (replace existing in the document library). The output would be as below:



  • All web parts would not be integrated into tabs cause of SharePoint specific behavior.
  • Only one instance of tabs could be used at a time in the current scenario which would be scaled further on usage scenarios.
  • Older browsers i.e. IE below 9 would require additional coding effort.

Thank you Srikar for the wonderful UI design.

Access SharePoint Online REST API via Postman with User Context


SharePoint Online(SPOL) allows remote applications to call the REST API with user impersonation. This article demonstrates how to access SPOL REST API and to the data from a SharePoint list in a tenant using Postman. However, outside of .NET the authentication piece is not so straightforward. App authentication solves this issue for registered apps but in this article you will see how remote user authentication can be achieved, regardless of platform.

The goal of this article is to provide examples of the HTTP requests which need to be made in order to authenticate SharePoint Online. It then provides an example of using the same technique to read data from a SharePoint list just to make sure it all works.


To play with this POC, you need the following:

Note: If you already have a subscription, you can use an existing account from your Office 365 subscription.

  • A SharePoint List with some data.
  • To send HTTP requests I am going to use Postman. Click here to go through Postman Getting Started details.
  • Fiddler to trace / debug

Note: The type of applications where this kind of approach may be necessary include: Java, PHP, or Informatica.

  • Keep the Chrome Browser and Fiddler Running for this POC. But you don’t need to login to SharePoint.

Steps Invovled

Before we read the data from SPOL, The REST API authentication piece comes in a few steps:

  • Generate Security Token
  • Generate Access Token
  • Get Request Digest

Generate Security Token

The first step is to provide a username and password of a user with Read access to the SharePoint List and the URL at which we want access to the SharePoint Online Security Token Service.

This is done by sending a POST request with the following XML as the request body to the URL


Note: Replace the following values with your data.

[User Name] – SPOL Account Username (example:

[Password]     – SPOL Account Password

[SharePoint Site URL] – SharePoint site URL where your list exists

Postman Configurations


(Request Body)


(Request Header)

Set Content-Type to application/x-www-form-urlencoded

Now hit Send button to view the Response. Your HTTP Response should be something like this:



Note down the security token value inside the wsse:BinarySecurityToken tag.

Important Note: If you get “Direct login to WLID is not allowed for this federated namespace” error, you have to follow different steps. Please refer the C# code for the tenants connected with ADFS.

Generate Access Token

Once the security token has been generated it must be used to fetch the access token. We can do this by sending a POST request to the following URL with the security token in the request body:

Postman Configurations


(Request Header)


(Request Body)

Now hit Send button to view the Response. Your HTTP Response should be something like this:

The response for this request contains some Cookies which must be passed as headers with all upcoming requests. Note down the values of the rtFa and FedAuth Cookies.



Get Request Digest

The request digest is a feature that ensures requests are coming from a single session. It must also be included with any POST requests.

We can get the request digest value by sending a POST request to the below URL:

Add rtFa and FedAuth Cookie values as headers with the request.

Postman Configurations


(Request Header)

Now hit Send button to view the Response. Your HTTP Response should be something like this:


(Request Response)

Note down the security token value inside the d:FormDigestValue tag including date and time zone values.

Read Data from SharePoint List

Now we are going to pass the d:FormDigestValue along with rtFa and FedAuth Cookie values in header section to access the SharePoint list via List REST API endpoint as shown below:

Postman Configurations


(Request Header)


(Request Response)

As you can see, we are able to read the SharePoint list data via REST API without login to SharePoint site in the browser.

Now you can try to mimic the same process in your own server-side language which supports web requests and work against SharePoint Online. The C# version of the same concept can be found here.

Issues Faced

If you are not able to generate REQUEST DIGEST value, follow the below article:

403 Forbidden from /_api/contextinfo when using Chrome Postman REST App



Package and Deploy SharePoint Framework WebPart

My previous article explains about how to create a simple Angular WebPart using SharePoint Framework Preview.

In this article, we will package and deploy the spfx-messagecenter-webpart assets to a remote CDN instead of using the local environment. We will use SharePoint Document Library as our CDN to deploy our assets but we can use our favorite CDN provider and upload the files.

To load the WebPart assets from CDN, we have to configure our CDN path in write-manifests.json file. This file can be found in the config folder.

cdnBasePath“: “

In this example, I have created a folder with name “MessageCenter” inside the CDN document library.

Save the file.

Switch to the console of the spfx-messagecenter-webpart project directory and run the following command to generate the assets to be uploaded in CDN

gulp bundle –ship

Generated assets can be found in spfx-messagecenter-webpart\temp\deploy folder

Run the following command to generate app file that needs to be uploaded in App Catalog site

gulp package-solution –ship

Generated spapp file can be found in spfx-messagecenter-webpart\sharepoint

Upload the spapp  file to the App Catalog. Since this is a full trust client-side solution, SharePoint will show you a popup and ask you to trust the client-side solution to deploy.

Click Deploy

Drag the files from spfx-messagecenter-webpart\temp\deploy folder and upload the assets inside

Now we can add spfx-messagecenter-webpart(you can find under custom group) to any SharePoint page. We are done.


deploy5.PNG Source Code