Completing Basic Operations using the SharePoint CSOM API and Windows PowerShell

Posted on Posted in Article, ITUnity, PowerShell Scripting, SharePoint Online

Update 10/25/2017: This article originally appeared on ITUnity.com but as that site has been decommissioned I’ve republished it here.

As you start working with and exploring the CSOM API with Windows PowerShell, you’re likely to be doing some searches looking for examples of how to use it. One of the more popular examples you’ll likely stumble upon is an MSDN article, How to: Complete basic operations using SharePoint 2013 client library code. In this article I want to go through some specific examples from that article so that you can see the C# code that you will typically encounter in most examples found on the Internet and what the equivalent PowerShell code would look like. In each example to follow I’ll show a snippet of the C# code from the article along with the equivalent PowerShell. Hopefully this will help you as you endeavor to translate other samples on your own.

Write to website’s properties

This example shows how to update the properties of a Web object.

ClientContext context = newClientContext(“http://SiteUrl”);

// The SharePoint web at the URL.

Web web = context.Web;

web.Title = “New Title”;

web.Description = “New Description”;

web.Update();

context.ExecuteQuery();

In the following PowerShell equivalent code note that I’m leveraging the Connect-SPOSite function detailed in the Connecting to SharePoint Online using the SharePoint CSOM API with Windows PowerShell article.

$context
= Connect-SPOSite https://SiteUrl

# The SharePoint web at the URL.

$web
=
$context.Web

$web.Title =
“New Title”

$web.Description =
“New Description”

$web.Update()

$context.ExecuteQuery()

Create a new SharePoint website

This example uses the WebCreationInformation class to create a new sub-site within an existing Web object.

ClientContext context = new
ClientContext(“http://SiteUrl”);

WebCreationInformation creation = new
WebCreationInformation();

creation.Url = “web1”;

creation.Title = “Hello web1”;

Web newWeb = context.Web.Webs.Add(creation);

// Retrieve the new web information.

context.Load(newWeb, w => w.Title);

context.ExecuteQuery();

In the preceding example the new sub-site is created and then just the title of the Web object is loaded for later use. As noted in the Loading Specific Values Using Lambda Expressions and the SharePoint CSOM API with Windows PowerShell article, because we can’t use lambda expressions we’ll replicate the same using the custom Load-CSOMProperties function that was defined in that article and which I assume is already loaded in memory.

$context
= Connect-SPOSite https://SiteUrl

$creation
= New-Object Microsoft.SharePoint.Client.WebCreationInformation

$creation.Url =
“web1”

$creation.Title =
“Hello web1”

$newWeb
= context.Web.Webs.Add($creation)

# Retrieve the new web information.

Load-CSOMProperties -object
$newWeb
-propertyNames @(“Title”)

$context.ExecuteQuery()

Retrieve all SharePoint lists in a web

This example is very similar to one shown in the Loading Specific Values Using Lambda Expressions and the SharePoint CSOM API with Windows PowerShell article where a collection of fields was retrieved but only populated specific properties. In this case, you’re doing effectively the same thing but with Lists instead.

ClientContext context = new
ClientContext(“http://SiteUrl”);

// The SharePoint web at the URL.

Web web = context.Web;

// Retrieve all lists from the server.

// For each list, retrieve Title and Id.

context.Load(web.Lists,

lists => lists.Include(list => list.Title,

list => list.Id));

// Execute query.

context.ExecuteQuery();

For this example I’ll show you how to do this two different ways. The first will just load the lists and let the CSOM API figure out which properties to load (basically most of the simple type properties), this is what you’d do if you didn’t have the Load-CSOMProperties function, which is what I’ll use for the second example (I’ll just put both statements one after the other rather than duplicate all the code):

$context
= Connect-SPOSite https://SiteUrl

# The SharePoint web at the URL.

$web
=
$context.Web

# Option 1: Let the API load what it wants to load

# Retrieve all lists from the server.

$context.Load($web.Lists)

# Option 2: Load specific properties

# Retrieve all lists from the server.

# For each list, retrieve Title and Id.

Load-CSOMProperties -parentObject
$web
-collectionObject
$web.Lists -propertyNames @(“Id”,
“Title”) -parentPropertyName
“Lists”

# Execute query.

$context.ExecuteQuery()

Create and update a SharePoint list

Many of the creation operations with CSOM use a data class, such as the WebCreationInformation class shown previously, rather than a method that would otherwise take in a whole lot of parameters. This example uses the ListCreationInformation class to create a new list instance.

ClientContext context = new
ClientContext(“http://SiteUrl”);

// The SharePoint web at the URL.

Web web = context.Web;

ListCreationInformation creationInfo = new
ListCreationInformation();

creationInfo.Title = “My List”;

creationInfo.TemplateType = (int)ListTemplateType.Announcements;

List list = web.Lists.Add(creationInfo);

list.Description = “New Description”;

list.Update();

context.ExecuteQuery();

The only thing worth pointing out in the following PowerShell equivalent code is that, with PowerShell, to get a specific enum value, such as the Announcements value used in the example, you use double colons (::) with the type name (just as you would with static properties or methods).

$context
= Connect-SPOSite https://SiteUrl

# The SharePoint web at the URL.

$web
=
$context.Web

$creationInfo
= New-Object Microsoft.SharePoint.Client.ListCreationInformation

$creationInfo.Title =
“My List”

$creationInfo.TemplateType =
[int][Microsoft.SharePoint.Client.ListTemplateType]::Announcements

$list
=
$web.Lists.Add($creationInfo)

$list.Description =
“New Description”

$list.Update()

$context.ExecuteQuery()

Retrieve items from a list

If you’re following along with the MSDN article you’ll note that I’ve skipped a few examples. The fact is, you should be seeing that there’s not a lot of changes you need to make to the C# code to get it to work within PowerShell. This next example uses the CamlQuery object to retrieve all items in a list and iterate over them.

ClientContext context = new
ClientContext(“http://SiteUrl”);

// Assume the web has a list named “Announcements”.

List announcementsList = context.Web.Lists.GetByTitle(“Announcements”);

// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope=”RecursiveAll”

// so that it grabs all list items, regardless of the folder they are in.

CamlQuery query = CamlQuery.CreateAllItemsQuery(100);

ListItemCollection items = announcementsList.GetItems(query);

// Retrieve all items in the ListItemCollection from List.GetItems(Query).

context.Load(items);

context.ExecuteQuery();

foreach (ListItem listItem in items)

{


// We have all the list item data. For example, Title.

label1.Text = label1.Text + “, “ + listItem[“Title”];

}

The preceding C# code populates a Label control that you might find in a WPF form but for our PowerShell equivalent we’ll just use the Select-Object cmdlet to output the values to the console.

$context
= Connect-SPOSite https://SiteUrl

# Assume the web has a list named “Announcements”.

$announcementsList
=
$context.Web.Lists.GetByTitle(“Announcements”)

# This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope=”RecursiveAll”

# so that it grabs all list items, regardless of the folder they are in.

$query
=
[Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100)

$items
=
$announcementsList.GetItems($query)

# Retrieve all items in the ListItemCollection from List.GetItems(Query).

$context.Load($items)

$context.ExecuteQuery()

$items
| select Title

Retrieve a specific field from the list

As noted in the MSDN documentation related to this example, you should use the GetFieldByInternalNameOrTitle method to retrieve a field from a field collection (whether it be from a List or Web object type). Unfortunately, the type of field returned is going to be the base Microsoft.SharePoint.Client.Field type rather than a more specific type appropriate to the field. In this case the field returned is the Title field which is a Text field so the type we’d expect to see is Microsoft.SharePoint.Client.FieldText.

ClientContext context = new
ClientContext(“http://SiteUrl”);

List list = context.Web.Lists.GetByTitle(“Shared Documents”);

Field field = list.Fields.GetByInternalNameOrTitle(“Title”);

FieldText textField = context.CastTo<FieldText>(field);

context.Load(textField);

context.ExecuteQuery();

As we look at the PowerShell equivalent the important bit to note is that PowerShell doesn’t make it easy for you to use generic methods such as the CastTo method shown above. To get around this you have to use some reflection to get the method passing in the type you want to cast to. Once you have the generic method descriptor you then call the Invoke method to execute the method.

$context
= Connect-SPOSite https://SiteUrl

$list
=
$context.Web.Lists.GetByTitle(“Shared Documents”)

$field
=
$list.Fields.GetByInternalNameOrTitle(“Title”)

$textField
=
$context.GetType().GetMethod(“CastTo”).MakeGenericMethod([Microsoft.SharePoint.Client.FieldText]).Invoke($context,
$field)

$context.Load($textField)

$context.ExecuteQuery()

Summary

As you’ve hopefully seen, working with the CSOM API to manipulate the data and structure of your site collections is reasonably straightforward, with just a few difficulties surrounding things such as lambda expressions and generics. If you’re a developer then you should feel right at home, if not a bit annoyed by PowerShell’s lack of conveniences we’ve come to think of as second nature with C#. If you don’t have a development background then you’ve got an uphill battle in front of you, but if you’ve paid close attention to the examples and use the information to discover and disseminate similar examples that you can find online, then you should be able to adapt very quickly.

One thing that I feel I need to point out is the fact that whether you’re working with native PowerShell cmdlets or those provided via the SharePoint Online Management Shell or if you’re working with the CSOM API, you are writing code and as such you should follow the same sort of common sense best practices to test and evaluate your code that you would with any compiled managed code that you might deploy to your servers. So if you’re working against your on-premises environment make sure that you have at least a test environment and ideally a test environment and a development environment so that you can verify your scripts before attempting to update your production environment. If you’re a SharePoint Online user then you should have a test tenant that you can test against. If you don’t have these test and development environments then I would argue that you don’t have a production environment and it’s just a matter of time before you make some sweeping change that you will quickly regret.

Leave a Reply

Your email address will not be published. Required fields are marked *

*