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.
1ClientContext context = newClientContext("http://SiteUrl");
2// The SharePoint web at the URL.
3Web web = context.Web;
4web.Title = "New Title";
5web.Description = "New Description";
6web.Update();
7context.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.
1$context = Connect-SPOSite "https://SiteUrl"
2# The SharePoint web at the URL.
3$web = $context.Web
4$web.Title = "New Title"
5$web.Description = "New Description"
6$web.Update()
7$context.ExecuteQuery()
Create a new SharePoint website
This example uses the WebCreationInformation class to create a new sub-site within an existing Web object.
1ClientContext context = new ClientContext("http://SiteUrl");
2WebCreationInformation creation = new WebCreationInformation();
3creation.Url = "web1";
4creation.Title = "Hello web1";
5Web newWeb = context.Web.Webs.Add(creation);
6// Retrieve the new web information.
7context.Load(newWeb, w => w.Title);
8context.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.
1$context = Connect-SPOSite "https://SiteUrl"
2$creation = New-Object Microsoft.SharePoint.Client.WebCreationInformation
3$creation.Url = "web1"
4$creation.Title = "Hello web1"
5$newWeb = context.Web.Webs.Add($creation)
6# Retrieve the new web information.
7Load-CSOMProperties -object $newWeb -propertyNames @("Title")
8$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.
1ClientContext context = new ClientContext("http://SiteUrl");
2// The SharePoint web at the URL.
3Web web = context.Web;
4// Retrieve all lists from the server.
5// For each list, retrieve Title and Id.
6context.Load(web.Lists,
7lists => lists.Include(list => list.Title,
8list => list.Id));
9// Execute query.
10context.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):
1$context = Connect-SPOSite https://SiteUrl
2# The SharePoint web at the URL.
3$web = $context.Web
4
5# Option 1: Let the API load what it wants to load
6# Retrieve all lists from the server.
7$context.Load($web.Lists)
8
9# Option 2: Load specific properties
10# Retrieve all lists from the server.
11# For each list, retrieve Title and Id.
12Load-CSOMProperties -parentObject $web -collectionObject $web.Lists -propertyNames @("Id", "Title") -parentPropertyName "Lists"
13
14# Execute query.
15$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.
1ClientContext context = new ClientContext("http://SiteUrl");
2// The SharePoint web at the URL.
3Web web = context.Web;
4ListCreationInformation creationInfo = new ListCreationInformation();
5creationInfo.Title = "My List";
6creationInfo.TemplateType = (int)ListTemplateType.Announcements;
7List list = web.Lists.Add(creationInfo);
8list.Description = "New Description";
9list.Update();
10context.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).
1$context = Connect-SPOSite "https://SiteUrl"
2# The SharePoint web at the URL.
3$web = $context.Web
4$creationInfo = New-Object Microsoft.SharePoint.Client.ListCreationInformation
5$creationInfo.Title = "My List"
6$creationInfo.TemplateType = [int][Microsoft.SharePoint.Client.ListTemplateType]::Announcements
7$list = $web.Lists.Add($creationInfo)
8$list.Description = "New Description"
9$list.Update()
10$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.
1ClientContext context = new ClientContext("http://SiteUrl");
2
3// Assume the web has a list named "Announcements".
4List announcementsList = context.Web.Lists.GetByTitle("Announcements");
5
6// This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
7// so that it grabs all list items, regardless of the folder they are in.
8CamlQuery query = CamlQuery.CreateAllItemsQuery(100);
9ListItemCollection items = announcementsList.GetItems(query);
10
11// Retrieve all items in the ListItemCollection from List.GetItems(Query).
12context.Load(items);
13context.ExecuteQuery();
14foreach (ListItem listItem in items)
15{
16 // We have all the list item data. For example, Title.
17 label1.Text = label1.Text + ", " + listItem["Title"];
18}
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.
1$context = Connect-SPOSite "https://SiteUrl"
2
3# Assume the web has a list named "Announcements".
4$announcementsList = $context.Web.Lists.GetByTitle("Announcements")
5
6# This creates a CamlQuery that has a RowLimit of 100, and also specifies Scope="RecursiveAll"
7# so that it grabs all list items, regardless of the folder they are in.
8$query = [Microsoft.SharePoint.Client.CamlQuery]::CreateAllItemsQuery(100)
9$items = $announcementsList.GetItems($query)
10
11# Retrieve all items in the ListItemCollection from List.GetItems(Query).
12$context.Load($items)
13$context.ExecuteQuery()
14$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
.
1ClientContext context = new ClientContext("http://SiteUrl");
2List list = context.Web.Lists.GetByTitle("Shared Documents");
3Field field = list.Fields.GetByInternalNameOrTitle("Title");
4FieldText textField = context.CastTo<FieldText>(field);
5context.Load(textField);
6context.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.
1$context = Connect-SPOSite "https://SiteUrl"
2$list = $context.Web.Lists.GetByTitle("Shared Documents")
3$field = $list.Fields.GetByInternalNameOrTitle("Title")
4$textField = $context.GetType().GetMethod("CastTo").MakeGenericMethod([Microsoft.SharePoint.Client.FieldText]).Invoke($context, $field)
5$context.Load($textField)
6$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.