powershell 中的延迟管道执行?

Deferred pipeline execution in powershell?

是否可以延迟流水线执行,或者修改之前的流水线?我正在寻找的是与 ODATA 端点交互的能力。我想使用标准(或自定义)powershell 命令来过滤数据,但我不想检索整个列表。例如

function Get-Records() {
    Invoke-RestMethod -Method Get -Uri $endpoint.Uri.AbsoluteUri ...
}

调用它可以 return 500 多条记录。通常我不想检索所有 500 条记录,有时我会。所以如果我需要全部 500 个,我可能只调用 Get-Records。但是如果我只想要特定的,我会想做

Get-Records | Where {$_.Name -eq 'me'}

上面还是把500条记录全都收到了,然后过滤下来。我会以某种方式希望 Where {$_.Name -eq 'me'} 将过滤器传回上一个管道 Invoke-RestMethod 并附加到 URI $filter=Name eq 'me'

您不能通过 post 处理过滤器(例如 Where-Object.

追溯修改管道

相反,您必须在源处过滤,使用数据提供程序的语法

这就是 PowerShell 的内置 cmdlet(例如 Get-ChildItem)通过 [string] 类型的 -Filter 参数 执行此操作的方式。

如果您想将 PowerShell 脚本块 作为过滤器传递,您必须自己将其转换为提供程序的语法 - 如果可能.

很少会有 PowerShell 表达式与提供程序的筛选功能的一对一映射,因此 也许更好的方法是要求用户直接使用提供程序的语法:

function Get-Records() {
  param(
   [Parameter(Mandatory)]
   [uri] $Uri
   ,
   [string] $Filter # Optional filter in provider syntax; e.g. "Name eq 'me'"
  )
    if ($Filter) { $Uri += '?$filter=' + $Filter }
    Invoke-RestMethod -Method Get -Uri $uri
}

# Invoke with a filter in the provider's syntax.
Get-Records "Name eq 'me'"

如果您确实希望用户能够传递脚本块,则必须自己翻译提供程序语法并确保翻译是可能的。

要稳健地执行此操作,您必须处理脚本块的 AST(抽象语法树),可通过其 .Ast 属性 访问,这是非常重要的。

如果您愿意对允许用户传递的表达式类型做出假设,您可以使用 字符串解析 ,例如下面的简单示例:


function Get-Records {
  param(
   [Parameter(Mandatory)]
   [uri] $Uri
   ,
   [scriptblock] $FilterScriptBlock # Optional filter
  )
    if ($FilterScriptBlock) { 
      # Translate the script block' *string representation*
      # into the provider-native filter syntax.
      # Note: This is overly simplistic in that it simply removes '$_.'
      #       and '-' before '-eq'.
      $Uri += '?$filter=' + $FilterScriptBlock -replace '$_\.' -replace '-(?=[a-z]+\b)'
    }
    Invoke-RestMethod -Method Get -Uri $Uri
}

# Invoke with a filter specified as a PowerShell script block.
Get-Records { $_.Name -eq 'me' }