-
-
Save glapointe/cc75574a1d4a225f401b to your computer and use it in GitHub Desktop.
<# | |
.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 { } | |
} |
Hi Gary,
same problem here. How to use it in this case?
$ctx.Load($list)
$ctx.Load($list.RootFolder)
$ctx.Load($list.RootFolder.Folders)
#clientContext.Load(collFolder, folders => folders.OrderByDescending(folder => folder.Name));
$ctx.Load($list.RootFolder.Folders, $items => $items.OrderByDescending($item => $item.Name)); # this will not work
#$ctx.Load($list.RootFolder.Files)
$ctx.ExecuteQuery()
I've been loving using this for my SharePoint CSOM auditing scripts but having recently had to switch authentication to MFA-compatible $authmanager, I'm finding that load-csomproperties now fails.
Used to be:
$SPOcredentials = Get-Credential #-username $username -Message "Please enter the password for $Username to use SPO Cmdlets"
$CSOMCredentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($SPOcredentials.Username, $SPOcredentials.Password)
$WebCTX = New-Object Microsoft.SharePoint.Client.ClientContext($WebURL)
And now it's
Connect-PnPOnline -useweblogin -url $weburl
$authManager = new-object OfficeDevPnP.Core.AuthenticationManager
$WebCtx = $authManager.GetWebLoginClientContext($WebURL)
And now a half dozen Load-csomproperty calls like:
$WebCTX.Load($List) $Webctx.ExecuteQuery() Load-CSOMProperties -object $List -propertyNames @('Title','BaseType') -executequery
which still work fine on non-MFA Microsoft.SharePoint.Client.SharePointOnlineCredentials'd Ctxs still works, but on AuthenticationManager auth'd connections I get this:
Load-CSOMProperties : Cannot process argument transformation on parameter 'object'. Cannot convert the
"Microsoft.SharePoint.Client.List" value of type "Microsoft.SharePoint.Client.List" to type
"Microsoft.SharePoint.Client.ClientObject".
At line:1 char:29
- Load-CSOMProperties -object $List -propertyNames @('Title','BaseType' ...
-
~~~~~
- CategoryInfo : InvalidData: (:) [Load-CSOMProperties], ParameterBindingArgumentTransformationException
- FullyQualifiedErrorId : ParameterArgumentTransformationError,Load-CSOMProperties
It's worth mentioning that it's not the only thing that breaks, I can't do CAML queries either.
Hi Gary,
I am facing one issue in case of using the nested lambda expressions.
I have posted my query at SO.
If you could look into it, I would be grateful to you.
Regards,
Koder101