Consuming the SharePoint 2013 REST API from PowerShell

Introduction

SharePoint 2013 introduces a Representational State Transfer (REST) service that is comparable to the  SharePoint CSOM and in addition to CSOM, REST API opens up a huge capabilities, in particular for administering and automating SharePoint Online when used with PowerShell.

Sending  REST requests to a SharePoint Online 

In the previous post we’ve already covered how to perform read operations by sending HTTPS requests to SharePoint RESTful web services. This time we are going to extend PowerShell script  in order to support all the CRUD operations.

The Invoke-RestSPO function sends  HTTPS requests to SharePoint REST web services that returns richly structured data (JSON)

Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.dll"
Add-Type –Path "C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
<#
.Synopsis
Sends an HTTP or HTTPS request to a SharePoint Online REST-compliant web service.
.DESCRIPTION
This function sends an HTTP or HTTPS request to a Representational State
Transfer (REST)-compliant ("RESTful") SharePoint Online web service.
.EXAMPLE
Invoke-SPORestMethod -Url "https://contoso.sharepoint.com/_api/web&quot;
.EXAMPLE
Invoke-SPORestMethod -Url "https://contoso.sharepoint.com/_api/contextinfo&quot; -Method "Post"
#>
Function Invoke-RestSPO(){
Param(
[Parameter(Mandatory=$True)]
[String]$Url,
[Parameter(Mandatory=$False)]
[Microsoft.PowerShell.Commands.WebRequestMethod]$Method = [Microsoft.PowerShell.Commands.WebRequestMethod]::Get,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$False)]
[String]$Metadata,
[Parameter(Mandatory=$False)]
[System.Byte[]]$Body,
[Parameter(Mandatory=$False)]
[String]$RequestDigest,
[Parameter(Mandatory=$False)]
[String]$ETag,
[Parameter(Mandatory=$False)]
[String]$XHTTPMethod,
[Parameter(Mandatory=$False)]
[System.String]$Accept = "application/json;odata=verbose",
[Parameter(Mandatory=$False)]
[String]$ContentType = "application/json;odata=verbose",
[Parameter(Mandatory=$False)]
[Boolean]$BinaryStringResponseBody = $False
)
if([string]::IsNullOrEmpty($Password)) {
$SecurePassword = Read-Host Prompt "Enter the password" AsSecureString
}
else {
$SecurePassword = $Password | ConvertTo-SecureString AsPlainText Force
}
$credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName, $SecurePassword)
$request = [System.Net.WebRequest]::Create($Url)
$request.Credentials = $credentials
$request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
$request.ContentType = $ContentType
$request.Accept = $Accept
$request.Method=$Method
if($RequestDigest) {
$request.Headers.Add("X-RequestDigest", $RequestDigest)
}
if($ETag) {
$request.Headers.Add("If-Match", $ETag)
}
if($XHTTPMethod) {
$request.Headers.Add("X-HTTP-Method", $XHTTPMethod)
}
if($Metadata -or $Body) {
if($Metadata) {
$Body = [byte[]][char[]]$Metadata
}
$request.ContentLength = $Body.Length
$stream = $request.GetRequestStream()
$stream.Write($Body, 0, $Body.Length)
}
else {
$request.ContentLength = 0
}
#Process Response
$response = $request.GetResponse()
try {
if($BinaryStringResponseBody -eq $False) {
$streamReader = New-Object System.IO.StreamReader $response.GetResponseStream()
try {
$data=$streamReader.ReadToEnd()
$results = $data | ConvertFrom-Json
$results.d
}
finally {
$streamReader.Dispose()
}
}
else {
$dataStream = New-Object System.IO.MemoryStream
try {
StreamCopyTo Source $response.GetResponseStream() Destination $dataStream
$dataStream.ToArray()
}
finally {
$dataStream.Dispose()
}
}
}
finally {
$response.Dispose()
}
}
# Get Context Info
Function Get-SPOContextInfo(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password
)
$Url = $WebUrl + "/_api/contextinfo"
Invoke-RestSPO $Url Post $UserName $Password
}
Function Stream-CopyTo([System.IO.Stream]$Source, [System.IO.Stream]$Destination)
{
$buffer = New-Object Byte[] 8192
$bytesRead = 0
while (($bytesRead = $Source.Read($buffer, 0, $buffer.Length)) -gt 0)
{
$Destination.Write($buffer, 0, $bytesRead)
}
}

view raw
Invoke-RestSPO.ps1
hosted with ❤ by GitHub

Request Digests

Since SharePoint requires the user to include a request digest value with each create, update and delete operation, an additional request is invoked using Get-SPOContextInfo function to request Context Info entity that contains request digest value.

 ETag

In order to avoid an additional request, “*” eTag value is used to match any eTag value resulting in the operation being performed regardless of the actual value.

Lists manipulation using REST API in PowerShell

This section contains sample code for all of the CRUD operations.

#———————————————————————————————-
# List CRUD operations via SharePoint REST API
#———————————————————————————————-
# Create a List
Function New-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$Title,
[Parameter(Mandatory=$True)]
[String]$BaseTemplate
)
$listMetadata = @{
__metadata = @{'type' = 'SP.List' };
Title = $Title;
BaseTemplate = $BaseTemplate} | ConvertTo-Json
$Url = $WebUrl + "/_api/lists"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO $Url Post $UserName $Password $listMetadata $contextInfo.GetContextWebInformation.FormDigestValue
}
# Update a List
Function Set-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$Identity,
[Parameter(Mandatory=$False)]
[String]$Title,
[Parameter(Mandatory=$False)]
[String]$Description
)
$listMetadata = @{
__metadata = @{'type' = 'SP.List' };
}
if($Title) {
$listMetadata['Title'] = $Title
}
if($Description) {
$listMetadata['Description'] = $Description
}
$listMetadata = $listMetadata | ConvertTo-Json
$Url = $WebUrl + "/_api/lists/getbytitle('" + $Identity + "')"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue Metadata $listMetadata ETag "*" XHTTPMethod "MERGE"
}
#Get List(s)
Function Get-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password
)
$Url = $WebUrl + "/_api/lists"
$data = Invoke-RestSPO $Url Get $UserName $Password
$data.results
}
#Delete a List
Function Remove-SPOList(){
Param(
[Parameter(Mandatory=$True)]
[String]$WebUrl,
[Parameter(Mandatory=$True)]
[String]$UserName,
[Parameter(Mandatory=$False)]
[String]$Password,
[Parameter(Mandatory=$True)]
[String]$Identity
)
$Url = $WebUrl + "/_api/lists/getbytitle('" + $Identity + "')"
$contextInfo = Get-SPOContextInfo $WebUrl $UserName $Password
Invoke-RestSPO Url $Url Method Post UserName $UserName Password $Password RequestDigest $contextInfo.GetContextWebInformation.FormDigestValue ETag "*" XHTTPMethod "DELETE"
}

view raw
ListOps-RestSPO.ps1
hosted with ❤ by GitHub

References

 

6 thoughts on “Consuming the SharePoint 2013 REST API from PowerShell

  1. Pingback: Working with folders and files via SharePoint 2013 REST in PowerShell | YASP Blog

  2. Great post Vadim !
    Though I was wondering how to add a list item using PowerShell and REST API ?
    Do you have any code example ?
    Thanks

    If I fill a “body” like shown below, I got a 400 message … (Content-Lengh calculated and RequestDigest retrieved)

    $body = @{d =
    @{
    __metadata=@{ ‘type’= ‘SP.Data.EntreListItem’
    ‘etag’= “1”
    };

    Title = “Sir”;
    NomId = 1;
    Name= “Bertrand”;

    };
    }

  3. I too am trying to use the Invoke-RestSPO call to add items to a sharepoint online list with no success. I get:

    Invoke-RestSPO : Cannot process argument transformation on parameter ‘Body’. Cannot convert value “{ ‘__metadata’: { ‘type’:
    ‘SP.Data.CongregationContactsListItem’ }, ‘Title’: ‘SomeData2’}” to type “System.Byte[]”. Error: “Cannot convert value “{ ‘__metadata’: { ‘type’:
    ‘SP.Data.CongregationContactsListItem’ }, ‘Title’: ‘SomeData2’}” to type “System.Byte”. Error: “Input string was not in a correct format.””
    At C:\Users\x\Documents\x\import.ps1:185 char:8
    + -Body $Body `
    + ~~~~~
    + CategoryInfo : InvalidData: (:) [Invoke-RestSPO], ParameterBindingArgumentTransformationException
    + FullyQualifiedErrorId : ParameterArgumentTransformationError,Invoke-RestSPO

    • Hi Dion, Can you please share more details on how could you add the List Item using Power Shell with REST. Awaiting you reply.

  4. Awesome post Vadim. Been trying to figure this out for a while. One suggestion on the results coming back I had to add this:
    #fix for ConvertFrom-Json : Cannot convert the JSON string because a dictionary that was converted from the string contains the duplicated keys ‘Id’ and ‘ID
    #http://stackoverflow.com/questions/22080350/convertfrom-json-cannot-convert-the-json-string-because-a-dictionary-that-was
    $data = $data.ToString().Replace(‘ID’, ‘_ID’)
    Just before the Convertyfrom-Json

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.