2015-12-17 3 views
2

Следующая отлично работает в C# (с использованием Microsoft.SharePoint.Client):Как сделать выражение lambda в PowerShell?

ClientContext sourceCtx = new ClientContext(sourceSiteUrl); 
sourceCtx.Credentials = new NetworkCredential("username", "password"); 
Site sourceSite = sourceCtx.Site; 
sourceCtx.Load(sourceSite, s => s.Usage); 
sourceCtx.ExecuteQuery(); 

Однако, я действительно хочу эту работу в PowerShell. Часть, которую я не могу понять, это выражение лямбда s => s.Usage. Глядя на this question я вижу, что ответ может быть, чтобы иметь встроенный ScriptBlock, поэтому я попытался следующее:

$lambda = { 
    param($s) 
    $s.Usage 
} 
$sourceCtx.Load($sourceSite, $lambda) 
$sourceCtx.ExecuteQuery(); 

Но это не удается следующим по методе Load:

Не может найти перегрузки для «load» и счетчик аргументов: «2».

В принципе, мне нужно делать какие-то преобразования типа в:

Expression<Func<T, Object>>[] 

Любые идеи?

+2

ли работа, если вы накладываете делегат правильно: '$ лямбда = [System.Func [Microsoft.SharePoint.Client.Site, Microsoft.SharePoint.Client.UsageInfo]] {параметр ($ s) возвращение $ s.Usage} '? –

ответ

3

В своем невежестве я думал, что это не было бы плохо .... Это не собирается быть весело, но это, кажется, единственный пример

http://www.itunity.com/article/loading-specific-values-lambda-expressions-sharepoint-csom-api-windows-powershell-1249

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() 

<

.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 { } 
} 
+0

Спасибо. Кто-то из моей компании нашел эту статью примерно в то же время, что и вы. Это похоже на соответствующий подход. –

1

если вы можете сделать это в C#, вы можете сделать это в powershell!

add-type @" 
namespace MyNamespace 
{ 
    public class MyProgram 
    { 
     public static string MyMethod (string args) 
     { 
      return args; 
     } 
    } 
} 
"@ 

[MyNamespace.MyProgram]::MyMethod('Hello World!') 
+0

Я думаю, что это сработает. Я рассматривал этот подход и все еще могу это сделать, но сначала я попытаюсь использовать подход @ Arcan.NET. –

+0

Это превосходный Кирк – Fidel