Working with Lists and List Items Using the SharePoint REST Service and Windows PowerShell

Gary Lapointe

by Gary Lapointe on 6/17/2015

Share this:
Print

Article Details

Date Revised:
7/3/2015

Applies to:
Fields REST API, Invoke-SPORestMethod, PSCustomObject, rest, Set-SPOCredentials, SharePoint Online site collection, Windows PowerShell


In the previous article, Using a Custom Windows PowerShell Function to Make SharePoint REST Service Calls, I detailed a custom utility function, Invoke-SPORestMethod, that can be used to make RESTful calls against a SharePoint REST Service endpoint. In this article I want to cover some common examples that illustrate how you can use the function to complete common tasks. As I did in a previous article with the CSOM API, I want to reference some examples found in a frequently referenced series of MSDN articles. You can find these articles under the Get started with the SharePoint 2013 REST service MSDN article. In those articles you’ll see numerous examples showing C# or JavaScript code and in some cases just the generic URL endpoint that you would call. In this article I want to walk through some of those examples so that you can see how you would accomplish the same tasks using PowerShell and the custom Invoke-SPORestMethod function. As with the CSOM examples, my hope is that this will help you as you endeavor to translate other samples on your own.

For the first set of examples I’ll walk through the examples from the Working with lists and list items with REST MSDN article. The examples in this article simply show the URL and HTTP method and headers and whatnot, as opposed to C# or JavaScript, so for the most part it should be just a matter of translating the information into what is needed to call the PowerShell function.

Retrieving lists and list properties with REST

Retrieve operations are the easiest and most straightforward operations that you can perform with REST as all you’re essentially doing is making a simple HTTP request. In the following example from the MSDN article, and the examples to follow, there is an Authorization header value being set. You don’t have to worry about that as the Invoke-SPORestMethod function sets the credentials for you so there’s no need to get an access token.

url: http://site url/_api/web/lists(guid'list GUID'),
method: GET
Headers:
     Authorization: "Bearer " + accessToken
     accept: "application/json;odata=verbose" or "application/atom+xml"

Converting this to PowerShell is pretty simple. In the figure below I’m loading the functions in the Invoke-SPORestMethod.ps1 file into memory, setting the credentials using the Set-SPOCredentials function, setting the REST URL to a variable, and then I call the Invoke-SPORestMethod function to retrieve the list details which I then output to the screen:

Use Invoke-SPORestMethod to retrieve a list using the list ID

Figure 1: Use Invoke-SPORestMethod to retrieve a list using the list ID

For subsequent examples, I’m not going to show the loading of the Invoke-SPORestMethod.ps1 file or the call to Set-SPORestCredentials as I’m going to assume that you’re using the same PowerShell session and therefore there’s no need to reload the file or provide the credentials again. Also, for the sake of keeping this article a little shorter, I won’t show the output as I’ve shown with Figure 1 and instead will just show the command you need to run.

For this next example I’m going to retrieve the same list but instead I’m going to use the GetByTitle method. Here’s the MSDN example:

url: http://site url/_api/web/lists/GetByTitle('Test')
method: GET
Headers:
     Authorization: "Bearer " + accessToken
     accept: "application/json;odata=verbose" or "application/atom+xml"

In the PowerShell sample below notice that I did not include the -Method or -JSONVerbosity parameters. This is because the default values are GET and Verbose, respectively, so providing the parameters is unnecessary.

$url = "https://contoso.sharepoint.com/_api/<u>web</u>/lists/GetByTitle('Documents')"
$list = Invoke-SPORestMethod -Url $url

Note that the MSDN examples have either “application/json;data=verbose” or “application/atom+xml” as the Accept header. In the examples here, I’ll always be working with JSON and not XML because the Invoke-SPORestMethod function was set for just JSON as this makes it easier to convert the results to a PSCustomObject. If you want to use XML instead of JSON you can extend the function to add a parameter or otherwise just change the value of the Accept and/or ContentType parameter (depending on whether you want to send and/or receive XML).

Working with lists by using REST

Creating a list using the REST service requires you to construct a JSON object that contains all the properties necessary to create the list. This example creates a new custom list called “Test”:

url: http://site url/_api/web/lists
method: POST
body: { '__metadata': { 'type': 'SP.List' }, 'AllowContentTypes': true, 'BaseTemplate': 100,
 'ContentTypesEnabled': true, 'Description': 'My list description', 'Title': 'Test' }
Headers:
     Authorization: "Bearer " + accessToken
     X-RequestDigest: form digest value
     accept: "application/json;odata=verbose"
     content-type: "application/json;odata=verbose"
     content-length:length of post body

To create the body data you can either create a PSCustomObject and convert it to a JSON string or just create the string directly. I prefer the latter because I think it’s just a bit quicker though perhaps a little harder to read (the PSCustomObject approach is less error prone). For the PowerShell equivalent of this example, I’ll show you how to do it using both approaches; however, for future examples, I’ll just use the string approach and will not create PSCustomObjects.

$url = "https://contoso.sharepoint.com/_api/web/lists"

# Option 1: Set metadata using PSCustomObject
$body = New-Object PSCustomObject -Property @{"__metadata" = (New-Object PSCustomObject -Property @{"type" = "SP.List"}); "AllowContentTypes" = $true; "BaseTemplate" = 100; "ContentTypesEnabled" = $true; "Description" = "My list description"; "Title" = "Test"}
$metadata = ConvertTo-Json $body -Compress

# Option 2: Set metadata using a manually constructed string
$metadata = "{'__metadata':{'type':'SP.List'},'Description':'My list description','BaseTemplate':100,'ContentTypesEnabled':true,'Title':'Test','AllowContentTypes':true}"

# Get the form digest
$digest = (Invoke-SPORestMethod -Url "https://contoso.sharepoint.com/_api/contextinfo" -Method "POST").GetContextWebInformation.FormDigestValue

# Create the list
$list = Invoke-SPORestMethod -Url $url -Method "POST" -Metadata $metadata -RequestDigest $digest

Notice that I used the Invoke-SPORestMethod function for not just creating the list but also for retrieving the form digest variable that is necessary for list creation. If you don’t provide this variable then you’ll get an error stating that the security context is invalid. For the sake of clarity in the examples that follow, I’m going to omit the call to retrieve the form digest and just assume that you have it in a variable for use.

To update a list you use essentially the same technique except that you now provide MERGE for the X-HTTP-Method header.

url: http://site url/_api/web/lists(guid'list GUID')
method: POST
body: { '__metadata': { 'type': 'SP.List' }, 'Title': 'New title' }
Headers:
     Authorization: "Bearer " + accessToken
     X-RequestDigest: form digest value
     IF-MATCH": etag or "*"
     X-HTTP-Method: MERGE,
     accept: "application/json;odata=verbose"
     content-type: "application/json;odata=verbose"
     content-length:length of post body

Note that for update operations you have to provide the IF-MATCH header (or, in the case of the Invoke-SPORestMethod function, the -ETag parameter). For the PowerShell example below, I’ve decided to use the GetByTitle list method to retrieve the list that was just created, as opposed to getting the list by ID:

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')"
$metadata = "{ '__metadata': { 'type': 'SP.List' }, 'Title': 'New title' }"
$list = Invoke-SPORestMethod -Url $url -Method "POST" -XHTTPMethod "MERGE" -Metadata $metadata -RequestDigest $digest -ETag "*"

In this case I’ve provided “*” for the -ETag parameter as I don’t care if someone else has updated the list. If I do care then I need to get the __metadata.etag property from the list object (see Figure 1, which shows the etag property in the output).

To add a field to the list you must again provide a JSON object containing all the properties you wish to apply to the new field, but this time you’ll use the _api/web/lists/Fields endpoint:

Url: url: http://site url/_api/web/lists(guid'list GUID')/Fields
Method:POST
Body: { '__metadata': { 'type': 'SP.Field' }, 'Title': 'field title', 'FieldTypeKind': FieldType value,'Required': 'true/false', 'EnforceUniqueValues': 'true/false','StaticName': 'field name'}
Headers:
     Authorization: "Bearer " + accessToken
     X-RequestDigest: form digest value
     content-type: "application/json;odata=verbose"
     content-length:length of post body

In the following PowerShell example, I’ve replaced the placeholder values from the MSDN article with actual values that you can use to create an actual field.

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('New title')/Fields"
$metadata = "{ '__metadata': { 'type': 'SP.Field' }, 'Title': 'My New Field', 'FieldTypeKind':2,'Required': 'true', 'EnforceUniqueValues': 'false','StaticName': 'MyNewField'}"
$field = Invoke-SPORestMethod -Url $url -Method "POST" -Metadata $metadata -RequestDigest $digest

So did you know that to create a Text field you need to set the FieldTypeKind property to 2? Neither did I until I started working on this article. So how do you find out this type of information? If you take a look at the Fields REST API reference you’ll see that within the document they point you to the SDK documentation for the Microsoft.SharePoint.Client.FieldType enumeration. It’s on this page that you can retrieve the numeric values you need for the FieldTypeKind property. So while I’m on the subject of the REST API reference, I encourage you to peruse the REST API reference and samples SDK articles for the other object types (lists, fields, users, webs, etc.) as you’ll find lots of additional examples and details about things like what methods are available and what properties you can retrieve or set.

To delete the list created in the previous examples you simply need to provide the endpoint to the list and then use the DELETE X-HTTP-Method header value and an appropriate IF-MATCH header value. Because this is a pretty simple operation, I’m going to omit the MSDN sample and just jump right to the PowerShell equivalent:

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('New title')"
Invoke-SPORestMethod -Url $url -Method "POST" -XHTTPMethod "DELETE" -RequestDigest $digest -ETag "*"

Working with list items by using REST

Working with list items is almost an identical process to working with lists – you just have a slightly different endpoint in that you are adding more information to the URL so that you can drill down to the item level.

This first item level example retrieves all items from the list. I don’t recommend doing this unless you know for certain that you don’t have a lot of items – you’re usually better off providing a filter to restrict the items returned.

url: http://site url/_api/web/lists/GetByTitle('Test')/items
method: GET
headers:
    Authorization: "Bearer " + accessToken
    accept: "application/json;odata=verbose" or "application/atom+xml"

As stated earlier, GET operations are the simplest:

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')/items"
$items = Invoke-SPORestMethod -Url $url

To retrieve a specific item, just add the item ID to the end of the URL (note that I’ve omitted the MSDN example as there’s minimal changes):

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')/items(1)"
$items = Invoke-SPORestMethod -Url $url

Note that if you provide the ID to an item that does not exist, you’ll get a 404 exception.

To create a new list item you once again need to construct a JSON object with the appropriate properties set. For the metadata type property make sure that you provide a value appropriate for the list.

url: http://site url/_api/web/lists/GetByTitle('Test')/items
method: POST
body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'Test'}
headers:
    Authorization: "Bearer " + accessToken
    X-RequestDigest: form digest value
     accept: "application/json;odata=verbose"
     content-type: "application/json;odata=verbose"
    content-length:length of post body

To get the metadata type property value you can retrieve an instance of the list and then get the ListItemEntityTypeFullName property value, as shown in the following example:

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')"
$list = Invoke-SPORestMethod -Url $url
$itemType = $list.ListItemEntityTypeFullName
$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')/items"
$metadata = "{ '__metadata': { 'type': '$itemType' }, 'Title': 'Test'}"
$item = Invoke-SPORestMethod -Url $url -Method "POST" -Metadata $metadata -RequestDigest $digest

To update an item you must change the endpoint such that it points to the specific item and then use the MERGE X-HTTP-Method header value along with the IF-MATCH header value. And like creating an item, you must also set the type to a value appropriate for the list.

url: http://site url/_api/web/lists/GetByTitle(‘Test')/items(item id)
method: POST
body: { '__metadata': { 'type': 'SP.Data.TestListItem' }, 'Title': 'TestUpdated'}
headers:
    Authorization: "Bearer " + accessToken
    X-RequestDigest: form digest value
    "IF-MATCH": etag or "*"
    "X-HTTP-Method":"MERGE",
    accept: "application/json;odata=verbose"
    content-type: "application/json;odata=verbose"
    content-length:length of post body

In the PowerShell example below I’m assuming that the $itemType variable is still valid:

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')/items(1)"
$metadata = "{ '__metadata': { 'type': '$itemType' }, 'Title': 'Test Updated'}"
$item = Invoke-SPORestMethod -Url $url -Method "POST" -XHTTPMethod "MERGE" -Metadata $metadata -RequestDigest $digest -ETag "*"

Deleting the list item is almost identical to deleting a list—simply provide the endpoint to the list item and then use the DELETE X-HTTP-Method header value and an appropriate IF-MATCH header value. As before, because this is a pretty simple operation, I’m going to omit the MSDN sample and just jump right to the PowerShell equivalent:

$url = "https://contoso.sharepoint.com/_api/web/lists/GetByTitle('Test')/items(1)"
Invoke-SPORestMethod -Url $url -Method "POST" -XHTTPMethod "DELETE" -RequestDigest $digest -ETag "*"

Summary

Working with the SharePoint REST Service is a simple and straightforward way to make changes to the Lists and List Items within your Site Collection. Following the patterns within this article and using the Invoke-SPORestMethod helper function you should be able to easily translate other similar examples. In order to assist you further in this translation, the next article in this series will focus on working with folders and files using the SharePoint REST Service.


Topic: PowerShell

Sign in with

Or register

  • I'm able to get items from a list but when I try to POST, I get a 403.

    PS D:\\PowershellScripts> $url = "https://xxxxxx/_api/Web/Lists/GetByTitle('Test')"

    PS D:\\PowershellScripts> $list = Invoke-SPORestMethod -Url $url

    PS D:\\PowershellScripts> $itemType = $list.ListItemEntityTypeFullName

    PS D:\\PowershellScripts> $itemType
    SP.Data.TestListItem

    PS D:\\PowershellScripts> $metadata = "{ '__metadata': { 'type': $itemType }, 'Name': 'Test'}"

    PS D:\\PowershellScripts> $url = "https://nike.sharepoint.com/sites/dev/kenlittle/_api/Web/Lists/GetByTitle('Test')/Items"

    PS D:\\PowershellScripts> $item = Invoke-SPORestMethod -Url $url -Method "POST" -Metadata $metadata -RequestDigest $digest
    Exception calling "GetResponse" with "0" argument(s): "The remote server returned an error: (403) Forbidden."
    At D:\\PowershellScripts\\Invoke-SPORestMethod.ps1:109 char:9
    + $response = $request.GetResponse()
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : WebException

    You cannot call a method on a null-valued expression.
    At D:\\PowershellScripts\\Invoke-SPORestMethod.ps1:155 char:13
    + $response.Dispose()
    + ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    You cannot call a method on a null-valued expression.
    At D:\\PowershellScripts\\Invoke-SPORestMethod.ps1:111 char:13
    + $streamReader = New-Object System.IO.StreamReader $response.GetRespo ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

  • I noticed (for an on-premise installation at least) that it is possible to get a list item using "http://site url/_api/web/lists/GetByTitle('Test')/items/GetByTitle('TestItem')", I was not able to actually perform an update using the same Uri. The item updates would only apply if I flipped the Uri to "http://site url/_api/web/lists/GetByTitle('Test')/items('ItemId')".
    Yes, I was trying to be lazy, but just an observation.
Connect with Experts