You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell中嵌套Lambda表达式转换问题:CSOM加载子站点属性失败

解决PowerShell中CSOM嵌套Lambda(Include)的加载问题

我来帮你搞定这个CSOM嵌套Lambda转换的问题——你遇到的核心问题是对Include方法的理解和PowerShell表达式树构造的错误,下面是具体的解决方案和解释:

方案一:直接构造表达式树调用Load和Include

这种方法不需要依赖自定义函数,直接用PowerShell还原C#中w => w.Include(s => s.ServerRelativeUrl)的逻辑:

# 1. 构造针对Web对象的属性选择Lambda(对应C#的s => s.ServerRelativeUrl)
$webParameter = [System.Linq.Expressions.ParameterExpression]::MakeVariable([Microsoft.SharePoint.Client.Web])
$serverRelativeUrlProp = [Microsoft.SharePoint.Client.Web].GetProperty("ServerRelativeUrl")
$propertyExpression = [System.Linq.Expressions.Expression]::Property($webParameter, $serverRelativeUrlProp)
$selectLambda = [System.Linq.Expressions.Expression]::Lambda(
    [System.Func[Microsoft.SharePoint.Client.Web, object]]$propertyExpression,
    $webParameter
)

# 2. 获取针对WebCollection的Include静态扩展方法
$includeMethod = [Microsoft.SharePoint.Client.ClientObjectQueryableExtensions].GetMethods() |
    Where-Object { $_.Name -eq "Include" -and $_.GetParameters().Length -eq 2 } |
    Select-Object -First 1 |
    ForEach-Object { $_.MakeGenericMethod([Microsoft.SharePoint.Client.Web]) }

# 3. 调用Include方法得到已指定投影的集合查询对象
$projectedWebs = $includeMethod.Invoke($null, @($clientContext.Web.Webs, $selectLambda))

# 4. 加载并执行查询
$clientContext.Load($projectedWebs)
$clientContext.ExecuteQuery()

# 5. 遍历子网站(现在集合已正确初始化)
foreach ($subsite in $clientContext.Web.Webs) {
    Write-Host "Subsite :" $subsite.ServerRelativeUrl
}

方案二:改进自定义的Load-CSOMProperties函数

如果想继续用你的自定义函数,可以扩展它来支持集合的Include场景:

function Load-CSOMProperties {
    param(
        [Parameter(Mandatory=$true)]
        [Microsoft.SharePoint.Client.ClientObject]$Object,
        [Parameter(Mandatory=$false)]
        [Microsoft.SharePoint.Client.ClientObjectCollection]$CollectionObject,
        [Parameter(Mandatory=$true)]
        [string[]]$PropertyNames,
        [Parameter(Mandatory=$false)]
        [switch]$IncludeCollectionItems
    )

    if ($CollectionObject -ne $null -and $IncludeCollectionItems.IsPresent) {
        # 获取集合元素的类型(比如WebCollection对应的Web类型)
        $elementType = $CollectionObject.GetType().GetGenericArguments()[0]
        
        # 构造元素的属性选择Lambda
        $paramExpr = [System.Linq.Expressions.ParameterExpression]::MakeVariable($elementType)
        $propertyExpr = [System.Linq.Expressions.Expression]::Property(
            $paramExpr,
            $elementType.GetProperty($PropertyNames[0])
        )
        $lambdaExpr = [System.Linq.Expressions.Expression]::Lambda(
            [System.Func[$elementType, object]]$propertyExpr,
            $paramExpr
        )

        # 获取并调用Include方法
        $includeMethod = [Microsoft.SharePoint.Client.ClientObjectQueryableExtensions].GetMethods() |
            Where-Object { $_.Name -eq "Include" -and $_.GetParameters().Length -eq 2 } |
            Select-Object -First 1 |
            ForEach-Object { $_.MakeGenericMethod($elementType) }
        
        $projectedCollection = $includeMethod.Invoke($null, @($CollectionObject, $lambdaExpr))
        $Object.Context.Load($projectedCollection)
    }
    else {
        # 原有单个对象的加载逻辑(保持你之前的实现)
        $paramExpr = [System.Linq.Expressions.ParameterExpression]::MakeVariable($Object.GetType())
        $propertyExpr = [System.Linq.Expressions.Expression]::Property(
            $paramExpr,
            $Object.GetType().GetProperty($PropertyNames[0])
        )
        $lambdaExpr = [System.Linq.Expressions.Expression]::Lambda(
            [System.Func[$Object.GetType(), object]]$propertyExpr,
            $paramExpr
        )
        $Object.Context.Load($Object, $lambdaExpr)
    }
}

# 使用改进后的函数加载子网站的ServerRelativeUrl
Load-CSOMProperties -Object $clientContext.Web -CollectionObject $clientContext.Web.Webs -PropertyNames @("ServerRelativeUrl") -IncludeCollectionItems
$clientContext.ExecuteQuery()

# 遍历子网站
foreach ($subsite in $clientContext.Web.Webs) {
    Write-Host "Subsite :" $subsite.ServerRelativeUrl
}

为什么你之前的调用会报错?

  1. 参数错误:你设置的-ParentPropertyName "Include"完全不对——Include不是Web对象的实例属性,而是一个静态扩展方法,不能通过访问Web的属性来调用它。
  2. 集合未初始化:错误中提到的"The collection has not been initialized"是因为在ExecuteQuery()之前,代码内部尝试枚举未加载的WebCollection,但核心问题还是表达式构造失败导致加载逻辑没有正确执行。

另外,你不需要两次ExecuteQuery(),只要正确构造Include表达式并完成加载,一次查询就足够获取所有需要的子网站属性。

内容的提问来源于stack exchange,提问作者Koder101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:40:37