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" | |
.EXAMPLE | |
Invoke-SPORestMethod -Url "https://contoso.sharepoint.com/_api/contextinfo" -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 { | |
Stream–CopyTo –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) | |
} | |
} |
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" | |
} |
References
Pingback: Working with folders and files via SharePoint 2013 REST in PowerShell | YASP Blog
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”;
};
}
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
I was able to add items to a list by using the SPO Rst powershell module located at http://www.falchionconsulting.com/PowerShellViewer/Default.aspx
Hi Dion, Can you please share more details on how could you add the List Item using Power Shell with REST. Awaiting you reply.
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