Wednesday, June 6, 2018

Posting updates to SharePoint Online via PowerShell and Rest API

In my previous blog office 365 powershell and restApi i demonstrated how to read/get data from SharePoint online site, here in this example we will Post updates.

Here are the important things to consider when posting updates to office 365:-

  1. We have to pass  X-RequestDigest value for the form digest HTTP header.
  2. If updating Lists/Document Library and items/documents to avoid concurrency conflicts we need to specify additional HTTP header with the name "IF-MATCH", which takes a value of Etag. Etag can be retrieved by retrieving the target entity(list or list item) with a GET method. This is included in the response HTTP headers and in the response content. In situations where we dont care about concurrency its ok to pass "*" as value.
I will use the PnPOnline msi PowerShell module to connect to Office 365 developer tenant of mine. Kindly read the office 365 powershell and restApi to understand how to use it and load the module.

Lets talk about the script here.

  • First we will Import the PowerShell module.

Import-Module "Microsoft.Online.SharePoint.PowerShell"

  • Next create a global webSession variable, we will add headers to this session via different functions as our code progresses.

#create webRequest session global Object
$Global:webSession = New-Object Microsoft.PowerShell.Commands.WebRequestSession


  • Lets create a function where we will pass the url of the SharePoint online site as a param and then will connect to it using Connect-PnPOnline function of PnP SharePoint Online Powershell:-



function Init-PnPSecuritySession{
param($targetSite)
$targetSiteUri = [System.Uri]$targetSite
#connect to the Sharepoint online site 
Connect-PnPOnline $targetSite
$context = (Get-PnPWeb).Context
$credentials = $context.Credentials
$authenticationCookies = $credentials.GetAuthenticationCookie($targetSiteUri, $true);

#set retrieved cookies as header to wenreq
$Global:webSession.Cookies.SetCookies($targetSiteUri,$authenticationCookies)
$Global:webSession.Headers.Add("Accept","application/json;odata=verbose");

}
Will retrieve the Context from PnP web and then grab the credentials and Authentication Cookie.
Next setup the authentication cookie value and include Accept header for content type.


We are using odata=verbose, instead we can use odata = minimalmetadata or odata = nometadata for reducing metadata returned after the rest call.


  • Next we will write a function in which we will make a rest call to ContextInfo namespace, retrieve the RequestDigest value and pass it to websession object:-
#function to get RequestDigest Value and set it with Http Header
function Init-PnPDigestValue{
param ($targetSite)

$contextInfoUrl = $targetSite + "_api/ContextInfo"
$webRequest = Invoke-WebRequest -Uri $contextInfoUrl
-Method Post -WebSession $Global:webSession

$jsonContextInfo = $webRequest.Content | ConvertFrom-Json
$digestValue = $jsonContextInfo.d.GetContextWebInformation.FormDigestValue
$Global:webSession.Headers.Add("X-RequestDigest",$digestValue)
}


  • Now lets add additional HTTP Headers, as its an Update we will user X-HTTP-Method "MERGE" or You can use "PATCH"  along with Post so that any writable property that is not specified in the content Metadata we are passing, will retain its current value.

$Global:webSession.Headers.Add("X-HTTP-Method","MERGE")
$Global:webSession.Headers.Add("IF-MATCH", "*")#optional
$Global:webSession.Headers.Add("content-type","application/json;odata=verbose")

We are keeping If-Match to *, this is optional and one can ignore it in this case. Its important to mention content-type.

  • Now lets declare the content, we will use stringified JSON object to update Title of the Web here. so it should be like this:-
$newContent = "{ '__metadata': { 'type': 'SP.Web' }, 'Title': 'PHLY CITY Site' }";
$Global:webSession.Headers.Add("content-length",$newContent.Length)

Our Object is SPweb and the property we are modifying is Title. so newContent is set accordingly and also an additional Header parameter is added to provide the content-length.

Now lets provide our url for sharepoint site and call the functions and then finally Invoke the web request:-

$targetSite = "https://phly.sharepoint.com/sites/phly/"
Init-PnPSecuritySession -targetSite $targetSite
Init-PnPDigestValue -targetSite $targetSite
$restCallUrl = $targetSite + "_api/web"

#Invoking the web request with websession and POST method.
$webRequest = Invoke-WebRequest -Uri $restCallUrl -Body $newContent  
-Method Post -WebSession $Global:webSession 


Save the entire script and execute it, it will ask you credentials to login to office 365 site and then will invoke the web request. you should be able to see the updated result on the site:-




No comments:

Post a Comment