Quantcast
Channel: SharePoint Pals - PowerShell
Viewing all articles
Browse latest Browse all 31

Lambda Expression in SharePoint CSOM PowerShell

$
0
0

In the CSOM, we might have using the Lambda Expression => frequently to load only the required properties. But the Lambda Expression is an Operator in C# not in PowerShell. When, we started coding with the PowerShell CSOM intensively, I required this Lambda to be replaced with its equivalent. When searching for that, Got a wonderful article by Gary here. Wanted to make it to be handy here as well.

To be more precise, let us see a scenario in C#.

 using (var ctx = authMgr.GetSharePointOnlineAuthenticatedContextTenant(siteUrl, userName, password))             {                 Web web = ctx.Web;                 ctx.Load(web.Lists);                 ctx.Load(web);                  ctx.ExecuteQueryRetry();                  List list = web.Lists.GetByTitle("D1");                 ctx.Load(list);                 ctx.Load(list, li => li.HasUniqueRoleAssignments);                 ctx.ExecuteQuery();                  System.Console.WriteLine(Convert.ToString(list.HasUniqueRoleAssignments));             } 
Gary has come up with a Method which is equivalent to our Lambda Expression – Load-CSOMProperties

The Lambda Expression method is as below. (Re-wrote from Gary’s article)

 <# .Synopsis     Facilitates the loading of specific properties of a Microsoft.SharePoint.Client.ClientObject object or Microsoft.SharePoint.Client.ClientObjectCollection object. .DESCRIPTION     Replicates what you would do with a lambda expression in C#.      For example, "ctx.Load(list, l => list.Title, l => list.Id)" becomes     "Load-CSOMProperties -object $list -propertyNames @('Title', 'Id')". .EXAMPLE     Load-CSOMProperties -parentObject $web -collectionObject $web.Fields -propertyNames @("InternalName", "Id") -parentPropertyName "Fields" -executeQuery     $web.Fields | select InternalName, Id .EXAMPLE    Load-CSOMProperties -object $web -propertyNames @("Title", "Url", "AllProperties") -executeQuery    $web | select Title, Url, AllProperties #>  function global:Load-CSOMProperties {     [CmdletBinding(DefaultParameterSetName='ClientObject')]     param (         # The Microsoft.SharePoint.Client.ClientObject to populate.         [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = "ClientObject")]         [Microsoft.SharePoint.Client.ClientObject]         $object,          # The Microsoft.SharePoint.Client.ClientObject that contains the collection object.         [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 0, ParameterSetName = "ClientObjectCollection")]         [Microsoft.SharePoint.Client.ClientObject]         $parentObject,          # The Microsoft.SharePoint.Client.ClientObjectCollection to populate.         [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1, ParameterSetName = "ClientObjectCollection")]         [Microsoft.SharePoint.Client.ClientObjectCollection]         $collectionObject,          # The object properties to populate         [Parameter(Mandatory = $true, Position = 1, ParameterSetName = "ClientObject")]         [Parameter(Mandatory = $true, Position = 2, ParameterSetName = "ClientObjectCollection")]         [string[]]         $propertyNames,          # The parent object's property name corresponding to the collection object to retrieve (this is required to build the correct lamda expression).         [Parameter(Mandatory = $true, Position = 3, ParameterSetName = "ClientObjectCollection")]         [string]         $parentPropertyName,          # If specified, execute the ClientContext.ExecuteQuery() method.         [Parameter(Mandatory = $false, Position = 4)]         [switch]         $executeQuery     )      begin { }     process {         if ($PsCmdlet.ParameterSetName -eq "ClientObject") {             $type = $object.GetType()         } else {             $type = $collectionObject.GetType()              if ($collectionObject -is [Microsoft.SharePoint.Client.ClientObjectCollection]) {                 $type = $collectionObject.GetType().BaseType.GenericTypeArguments[0]             }         }          $exprType = [System.Linq.Expressions.Expression]         $parameterExprType = [System.Linq.Expressions.ParameterExpression].MakeArrayType()         $lambdaMethod = $exprType.GetMethods() | ? { $_.Name -eq "Lambda" -and $_.IsGenericMethod -and $_.GetParameters().Length -eq 2 -and $_.GetParameters()[1].ParameterType -eq $parameterExprType }         $lambdaMethodGeneric = Invoke-Expression "`$lambdaMethod.MakeGenericMethod([System.Func``2[$($type.FullName),System.Object]])"         $expressions = @()          foreach ($propertyName in $propertyNames) {             $param1 = [System.Linq.Expressions.Expression]::Parameter($type, "p")             try {                 $name1 = [System.Linq.Expressions.Expression]::Property($param1, $propertyName)             } catch {                 Write-Error "Instance property '$propertyName' is not defined for type $type"                 return             }             $body1 = [System.Linq.Expressions.Expression]::Convert($name1, [System.Object])             $expression1 = $lambdaMethodGeneric.Invoke($null, [System.Object[]] @($body1, [System.Linq.Expressions.ParameterExpression[]] @($param1)))               if ($collectionObject -ne $null) {                 $expression1 = [System.Linq.Expressions.Expression]::Quote($expression1)             }             $expressions += @($expression1)         }           if ($PsCmdlet.ParameterSetName -eq "ClientObject") {             $object.Context.Load($object, $expressions)             if ($executeQuery) { $object.Context.ExecuteQuery() }         } else {             $newArrayInitParam1 = Invoke-Expression "[System.Linq.Expressions.Expression``1[System.Func````2[$($type.FullName),System.Object]]]"             $newArrayInit = [System.Linq.Expressions.Expression]::NewArrayInit($newArrayInitParam1, $expressions)              $collectionParam = [System.Linq.Expressions.Expression]::Parameter($parentObject.GetType(), "cp")             $collectionProperty = [System.Linq.Expressions.Expression]::Property($collectionParam, $parentPropertyName)              $expressionArray = @($collectionProperty, $newArrayInit)             $includeMethod = [Microsoft.SharePoint.Client.ClientObjectQueryableExtension].GetMethod("Include")             $includeMethodGeneric = Invoke-Expression "`$includeMethod.MakeGenericMethod([$($type.FullName)])"              $lambdaMethodGeneric2 = Invoke-Expression "`$lambdaMethod.MakeGenericMethod([System.Func``2[$($parentObject.GetType().FullName),System.Object]])"             $callMethod = [System.Linq.Expressions.Expression]::Call($null, $includeMethodGeneric, $expressionArray)                          $expression2 = $lambdaMethodGeneric2.Invoke($null, @($callMethod, [System.Linq.Expressions.ParameterExpression[]] @($collectionParam)))              $parentObject.Context.Load($parentObject, $expression2)             if ($executeQuery) { $parentObject.Context.ExecuteQuery() }         }     }     end { } }  
After this, we can use the method Load-CSOMProperties which is similar to our Lambda Expression.

The actual Usage is as follows.

 # Add Necessary Client DLLs Add-Type -Path "C:\SATHISH\ClientDLLs\Microsoft.SharePoint.Client.dll"  Add-Type -Path "C:\SATHISH\ ClientDLLs\Microsoft.SharePoint.Client.Runtime.dll"   #Get the UserName and Password $UserName = "sathish@*******.onmicrosoft.com" $password = Read-Host 'Enter Password' -AsSecureString $Url = "https://*******.sharepoint.com/sites/DeveloperSite/" $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($UserName , $Password)  $context = New-Object Microsoft.SharePoint.Client.ClientContext($Url) $context.Credentials = $credentials            #Get the Web $web = $context.Web $context.Load($web) #Get the Lists in the Web $context.Load($web.Lists) $context.ExecuteQuery()   #Get a specific List $list = $web.Lists.GetByTitle("RamList")  #Usage of Lambda Operator.  I am Loading the HasUniqueRoleASsignments similar to #the Lambda Operator  Load-CSOMProperties -object $list -propertyNames @("HasUniqueRoleAssignments")  $context.ExecuteQuery();  Write-Host $list.HasUniqueRoleAssignments  

Happy Coding,

Sathish Nadarajan.


Viewing all articles
Browse latest Browse all 31

Trending Articles