Loading Specific Values Using Lambda Expressions and the SharePoint CSOM API with 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.

In the article, Using the SharePoint CSOM API with SharePoint Online and Windows PowerShell, I explained that when you call the ClientContext object’s Load method that only a subset of properties are typically loaded, usually most of the simple types, and that you’ll need to make another call to the Load method to get additional properties. But what if you want to explicitly load those additional properties or explicitly restrict the properties that are loaded to an even smaller set of properties? If you’re using C# you can do this very easily using something known as lambda expressions. Lambda expressions let us do all kinds of different things, but for our purposes here it essentially allows you to specify the properties to load. Consider the following C# example, which explicitly loads just the AllProperties collection object and the Title and Url properties of the Web object:

var web = ctx.Web;

ctx.Load(web, w => w.AllProperties, w => w.Title, w => w.Url);

ctx.ExecuteQuery();

This next example loads the Web‘s Fields collection populating just the InternalName and Id properties of each Field object within the collection:

var web = ctx.Web;

ctx.Load(web, w => w.Fields.Include(f => f.Id, f=> f.InternalName));

ctx.ExecuteQuery();

 

If you’re new to lambda expressions, the syntax might look a little odd and a breakdown of its syntax is out of scope for this article, but in general this looks pretty straightforward, right? So now you should be asking if you can do that in PowerShell. The answer is, sort of. Unfortunately, you can’t do lambda expressions in PowerShell but it is possible to achieve the same thing – with a Godzilla-sized amount of code! Well, maybe not that much code, but a whole lot by comparison. Lambda expressions are ultimately just a C# language construct that, behind the scenes, is compiled down to .NET code (other languages like VB.NET have lambda expression support as well but the syntax is different). The following snippet is an example of what the code for the first of the two previous examples would look like if written in .NET 2.0 without the convenience of the lambda expression syntax:

ParameterExpression expression;

Web clientObject = ctx.Web;

ctx.Load<Web>(clientObject, new
Expression<Func<Web, object>>[] { Expression.Lambda<Func<Web, object>>(Expression.Property(expression = Expression.Parameter(typeof(Web), “w”), (MethodInfo) methodof(Web.get_AllProperties)), new
ParameterExpression[] { expression }), Expression.Lambda<Func<Web, object>>(Expression.Property(expression = Expression.Parameter(typeof(Web), “w”), (MethodInfo) methodof(Web.get_Title)), new
ParameterExpression[] { expression }), Expression.Lambda<Func<Web, object>>(Expression.Property(expression = Expression.Parameter(typeof(Web), “w”), (MethodInfo) methodof(Web.get_Url)), new
ParameterExpression[] { expression }) });

ctx.ExecuteQuery();

 

Makes perfect sense and should be nice and easy to translate this into PowerShell, right? Yeah, not so much! It’s a major pain and the second example is even worse so I’m not even going to show it here (really, don’t even try to understand what’s going on with that code – it’s not worth it). But all is not lost as I’ve taken the time to do the translation for you, and I even packaged it all up in a nice and easy-to-use function that I called Load-CSOMProperties:

I’m not going to bother you with a detailed analysis of all this code – it’s just too darn confusing and would take away from the point of this article. The thing you need to know is how to use it, so if you were to rewrite the original examples from this article as their PowerShell equivalents, but using this handy dandy new function, you’d get the following:

C:\Scripts\Load-CSOMProperties.ps1

 

$web
=
$ctx.Web

Load-CSOMProperties
-object
$web
-propertyNames @(“AllProperties”, “Url”, “Title”)

$ctx.ExecuteQuery()

 

 

$web
=
$ctx.Web

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

$ctx.ExecuteQuery()

 

Notice that there’s two different ways of calling the function based on whether we’re trying to load properties of an object directly (first example) or if we’re trying to load properties of a child object (second example). For the first example you simply need to provide the object that contains the properties you wish to load along with an array of the property names to load. The second example requires a bit more information to get the job done – specifically, it needs the parent object (the object that contains the collection to load), the collection object itself along with an array list of the properties to load for each item in the collection, and finally, the name of the property associated with the collection object.

I’ve done a reasonable amount of testing with the function and it worked for me without any issues but obviously it’s very complex, and with complexity comes the probability that errors will occur, so use at your own risk.

What about the Retrieve Methods?

If you’ve worked with the CSOM objects before you may have noticed that there are two public Retrieve methods which you could potentially use to load specific scalar properties of a given object. One of these two Retrieve methods, specifically the one that takes in a string array of parameter names, allows you to do almost exactly what the Load-CSOMProperties custom function is doing in the previous example where I demonstrated loading the AllProperties, Url and Title properties of the Web object. However, there are limitations to what the Retrieve method can do – you can only use it to load scalar properties (strings, integers, Booleans, etc.) and it doesn’t help you when it comes to loading specific properties of items within a collection (as demonstrated in the second example above). Because of the scalar limitation you couldn’t, for example, use it to load the AllProperties property as shown in the example. The last issue related to the methods is one of support – if you look at the MSDN documentation for the methods you should notice the following description:

Retrieves scalar properties associated with the object. This member is reserved for internal use and is not intended to be used directly from your code.

So even though the methods are public and technically you can use them, due to the limitations related to scalar properties and collections and mostly due to Microsoft’s disclaimer around their use I actually don’t use these methods and instead just rely on the Load-CSOMProperties function. It better achieves my goal of mimicking what I can do with lambda expressions and I don’t have to worry about Microsoft pulling or changing the method in a later build and therefore breaking code that might depend on it.

Summary

PowerShell is an immensely useful tool and you can do amazing things with it from a programming perspective. However, it’s still a bit behind more advanced languages such as C#, so every once in a while you’re likely to come across some C# code that just doesn’t translate easily to PowerShell. In this case, lambda expressions and PowerShell don’t easily mix, but with a little creativity it is possible to hack your way through the gap so that you can still write some reasonably elegant code with the help of a few helper functions. In the article, Completing Basic Operations using the SharePoint CSOM API and Windows PowerShell, you will get a chance to see how we can use this helper function to assist with the translation from C# to PowerShell of some common MSDN examples. Often times it won’t be necessary to load specific properties and you’ll be content with loading all properties or just one at a time thereby making this hack of a function unnecessary, but it is nice to know that when the situation arises where it is necessary or otherwise beneficial, that you’ve got something like this in your toolbox.

Leave a Reply

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

*