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' }
是否可以延迟流水线执行,或者修改之前的流水线?我正在寻找的是与 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' }