支持词法范围 ScriptBlock 参数(例如Where-Object)

2023-12-23

考虑以下任意函数和测试用例:

Function Foo-MyBar {
    Param(
        [Parameter(Mandatory=$false)]
        [ScriptBlock] $Filter
    )

    if (!$Filter) { 
        $Filter = { $true } 
    }

    #$Filter = $Filter.GetNewClosure()

    Get-ChildItem "$env:SYSTEMROOT" | Where-Object $Filter   
}

##################################

$private:pattern = 'T*'

Get-Help Foo-MyBar -Detailed

Write-Host "`n`nUnfiltered..."
Foo-MyBar

Write-Host "`n`nTest 1:. Piped through Where-Object..."
Foo-MyBar | Where-Object { $_.Name -ilike $private:pattern  }

Write-Host "`n`nTest 2:. Supplied a naiive -Filter parameter"
Foo-MyBar -Filter { $_.Name -ilike $private:pattern }

在测试 1 中,我们通过管道传输结果Foo-MyBar通过一个Where-Object过滤器,它将返回的对象与私有范围变量中包含的模式进行比较$private:pattern。在这种情况下,这将正确返回 C:\ 中以字母开头的所有文件/文件夹T.

在测试 2 中,我们直接将相同的过滤脚本作为参数传递给Foo-MyBar。然而,到了那时Foo-MyBar开始运行过滤器,$private:pattern不在范围内,因此不会返回任何项目。

我明白why情况就是这样——因为 ScriptBlock 传递给Foo-MyBar不是一个closure,所以不会关闭$private:pattern变量并且该变量丢失。

我从评论中注意到,我之前有一个有缺陷的第三个测试,它试图通过 {...}.GetNewClosure(),但这不会关闭私有范围的变量 - 感谢 @PetSerAl 帮助我澄清这一点。

问题是,如何Where-Object捕捉价值$private:pattern在测试 1 中,我们如何在我们自己的函数/cmdlet 中实现相同的行为?

(最好不需要调用者必须了解闭包,或者知道将其过滤器脚本作为闭包传递。)

我注意到,如果我取消注释$Filter = $Filter.GetNewClosure()里面的线Foo-MyBar,那么它永远不会返回任何结果,因为$private:pattern丢失了。

(正如我在顶部所说,这里的函数和参数是任意的,作为我真正问题的最短形式再现!)


给出的示例不起作用,因为默认情况下调用函数将进入新的作用域。Where-Object仍将调用过滤器脚本而不输入一个,但该函数的范围没有private多变的。

有三种方法可以解决这个问题。

将函数放在与调用者不同的模块中

每个模块都有一个SessionState它有自己的堆栈SessionStateScopes。每一个ScriptBlockSessionStateis 被解析到.

如果调用模块中定义的函数,则会在该模块的范围内创建一个新作用域SessionState,但不在顶层内SessionState。因此当Where-Object调用过滤器脚本而不输入新的范围,它在当前范围内执行此操作SessionState到那个ScriptBlock被绑住了。

这有点脆弱,因为如果您想从模块中调用该函数,那么您不能。也会有同样的问题。

使用点源运算符调用该函数

您很可能已经知道点源运算符 (.)用于调用脚本文件而不创建新范围。这也适用于命令名称和ScriptBlock对象。

. { 'same scope' }
. Foo-MyBar

但请注意,这将在当前范围内调用该函数SessionState 该函数来自,所以你不能依赖.始终执行在caller's当前范围。因此,如果您调用与不同的关联的函数SessionState使用点源运算符 - 例如在(不同的)模块中定义的函数 - 它可能会产生意想不到的效果。创建的变量将持续到将来的函数调用,并且函数本身中定义的任何辅助函数也将持续存在。

编写 Cmdlet

编译命令 (cmdlet) 在调用时不会创建新作用域。您还可以使用类似的 APIWhere-Object使用(虽然不完全相同)

这是如何实施的粗略实施Where-Object使用公共 API

using System.Management.Automation;

namespace MyModule
{
    [Cmdlet(VerbsLifecycle.Invoke, "FooMyBar")]
    public class InvokeFooMyBarCommand : PSCmdlet
    {
        [Parameter(ValueFromPipeline = true)]
        public PSObject InputObject { get; set; }

        [Parameter(Position = 0)]
        public ScriptBlock FilterScript { get; set; }

        protected override void ProcessRecord()
        {
            var filterResult = InvokeCommand.InvokeScript(
                useLocalScope: false,
                scriptBlock: FilterScript,
                input: null,
                args: new[] { InputObject });

            if (LanguagePrimitives.IsTrue(filterResult))
            {
                WriteObject(filterResult, enumerateCollection: true);
            }
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

支持词法范围 ScriptBlock 参数(例如Where-Object) 的相关文章

  • `list()` 被认为是一个函数吗?

    list显然是内置类型 https docs python org 3 library stdtypes html list在Python中 我看到底下有一条评论this https stackoverflow com a 53645813
  • 如何在 PowerShell 中将长命令拆分为多行

    如何在 PowerShell 中获取如下所示的命令并将其拆分为多行 C Program Files IIS Microsoft Web Deploy msdeploy exe verb sync source contentPath c w
  • PowerShell 中转义反引号“`”和反斜杠“\”有什么区别?

    我知道两者都在 PowerShell 中使用 但用于不同的上下文 互联网上关于这个主题的信息很少 唯一谈论这个主题的网站 没有让我理解这个概念 是 https www rlmueller net PowerShellEscape htm h
  • java中将函数作为参数传递

    我正在熟悉 Android 框架和 Java 并希望创建一个通用的 NetworkHelper 类 该类将处理大部分网络代码 使我能够从中调用网页 我按照developer android com 上的这篇文章创建了我的网络类 http d
  • 全局变量用例

    我有几个脚本和模块 它们使用全局变量来完成很多事情 我的日志记录可以采用以下三种形式之一 简洁 详细和验证 没有实际操作的详细日志记录 仅验证提供的数据 我还有许多函数 它们根据运行的上下文 用户或机器 而做出不同的响应 并且正在执行的操作
  • PowerShell 脚本,用于将超过 x 天的文件和文件夹(包括子文件夹)从一个位置移动到另一个位置

    我开发了一个 PowerShell 脚本 它运行得非常好 唯一的挑战是子文件夹中的文件没有移动到目的地 get childitem Path servername location where object LastWriteTime lt
  • SQL Server:删除除系统数据库之外的所有数据库

    在 PowerShell 中 我使用以下代码删除所有非系统 SQL Server 数据库 invoke sqlcmd ServerInstance sqlInstanceName U sqlUser P sqlPass Query EXEC
  • 如何从事件处理程序返回indexedDB查询结果?

    我必须从indexedDB返回查询结果 但结果只能在onsuccess事件处理程序 1 function listPeople 4 var open indexedDB open AccordionDatabase 1 5 res 6 7
  • 为什么 `obj.foo = function() { };` 没有将名称 `foo` 分配给函数?

    从 ES2015 ES6 开始 函数有了专有名称 包括官方名称 name属性 而函数创建时的赋值除了明显的函数声明和命名函数表达式之外还有多种方式 比如给变量赋值 函数的名字设置为变量的名字 给对象属性赋值 函数的名称设置为属性的名称 甚至
  • 行方向变异的有效方法

    我有两个数据框 dfUsers and purchases使用以下代码生成 set seed 1 library data table dfUsers lt data table user letters 1 5 startDate sam
  • 如何忽略警告错误?

    我有以下 PowerShell 脚本 它获取给定 IP 地址内计算机的 NetBIOS 名称 我正在使用管道将结果转储到文本文件中 问题是 如果 IP 地址不可用 则会打印警告 这是 PowerShell 脚本 function Get C
  • PSExec 中的会话 ID

    Psexec 无法在远程会话上为我显示记事本 GUI 因此 我尝试获取会话 ID 如下所示 c Users Amitra Downloads PSTools gt PsExec u administrator p force 135 20
  • VB.NET - 类中的扩展函数?

    我正在尝试创建一个类库 其中包含将二进制整数转换为十进制的函数 反之亦然 这样我就可以将其导入到另一个项目中 而无需重写该函数 它工作得很好 这是课程的一部分 Public Class BinaryDenary Public Shared
  • 当放入对象方法内时,引用拉入封装方法的方法会移出范围

    当我将引用拉入包的方法放入另一个方法中时 它会离开范围并失败 执行此操作的正确方法是什么 我尝试玩弄 自我 但我是新人 但没有成功 所需的解决方案 不起作用 返回错误 nil NilClass 的未定义方法 accounts NoMetho
  • $scope.$digest 之后立即触发事件

    在我的 AngularJS 应用程序中 有几个点我想等待 scope被处理到 DOM 中 然后在其上运行一些代码 就像 jQueryfadeIn 例如 有没有办法监听某种 digestComplete 消息 我当前的方法是 设置后立即 sc
  • Powershell 查询的升序和降序

    下面的查询将列出 powershell 中的 cmdlet get command CommandType cmdlet Group Object Property verb 因为我需要按降序对列数进行排序 然后按升序对列进行命名 以下查询
  • 从输出中删除空行

    我有这个脚本 for true Write Host Get Date UFormat Y m d H M S ping n 1 10 10 50 203 Select String SimpleMatch Pinging Context
  • 如何在 SQLite 中获取最后插入的 ID?

    SQLite 中是否有任何内置函数可以获取最后插入的行 ID 例如 在 mysql 中我们有LAST INSERT ID 这种功能 对于 sqlite 任何可用于执行相同过程的函数 请帮我 Thanks SQLite 这可以使用SQLite
  • 使用 Powershell SQL 将数据提取到 Excel

    我想使用 powershell 将数据从 SQL Server 提取到新的 excel 文件 对于小型数据集 我的代码可以工作 但某些表的行数超过 100 000 行 这将需要很长时间 我不在 SQl 服务器中使用该实用程序的原因是因为我想
  • 抑制数组列表添加方法管道输出

    我正在使用数组列表来构建日志项序列以供稍后记录 工作起来很不错 但是 Add 方法将当前索引发送到管道 我可以通过将其发送到 null 来解决这个问题 如下所示 strings Add junk gt null 但我想知道是否有某种机制可以

随机推荐

  • 设置初始值 Angular 2 反应式数组

    我正在尝试设置 Angular 2 反应形式 formArray 对象的初始值 尽管用于设置表单值的 json 对象包含具有多个条目的数组值 但仅显示第一个条目 并且 form value 也仅显示第一个条目 我正在使用语法
  • 使用 WhatsApp URL 方案发送 URL 和文本

    我正在尝试使用 WhatsApp 的自定义 URL 方案发送一些带有 URL 的文本 显然只有一个有效参数可用于此目的 text NSURL whatsappURL NSURL URLWithString whatsapp send tex
  • 是否有一个用于长类型的函数 Math.Pow(A,n) ?

    我正在测试一个小的 C 程序片段 short min short short int Math Pow 2 15 short max short short int Math Pow 2 15 1 Console WriteLine The
  • 向 ggplot2 绘图添加辅助 y 轴 - 使其完美

    添加辅助 y 轴 缩放原始 y 轴之一 这个话题并不新鲜 例如 它已被触动过多次在这个 ggplot2 谷歌组线程上 http groups google com group ggplot2 browse thread thread b48
  • 更改 Finder 文件夹背景颜色 AppleScript

    我正在尝试在重复循环中更改 Finder 的背景颜色 tell application Finder set windowCount to count windows if windowCount gt 0 then check if wi
  • 垃圾收集应该已删除对象,但 WeakReference.IsAlive 仍返回 true

    我有一个我希望通过的测试 但垃圾收集器的行为并不像我想象的那样 Test public void WeakReferenceTest2 var obj new object var wRef new WeakReference obj wR
  • tm 使用示例

    你能举个使用的例子吗tm 我不知道如何初始化struct 当前日期以此格式写入y m d 如何使用tm结构 call time 获取当前日期 时间 自 1970 年 1 月 1 日以来的秒数 call localtime to get st
  • .NET Core:从 API JSON 响应中删除空字段

    在 NET Core 1 0 所有 API 响应 的全局级别上 如何配置 Startup cs 以便在 JSON 响应中删除 忽略空字段 使用 Newtonsoft Json 您可以将以下属性应用于属性 但我想避免将其添加到每个属性 Jso
  • 将文件保存到 Azure Blob 中

    我正在使用下面的 python 代码将文件保存到本地文件夹中 我想将此文件直接保存到 Azure Blob 中 我不希望文件存储在本地然后上传到 blob 我尝试在文件夹变量中给出 blob 位置 但它不起作用 我有一个 excel 文件
  • 如何使用 Webpack 设置 React 组件的私有共享库

    我在多个 Webpack 项目中使用了许多 React 组件 我想通过 NPM 共享它们 所以我很自然地 将这些组件放入 私有 GitHub 存储库中 将该存储库添加到主项目中package json 为了能够同时在组件库上进行开发 我使用
  • HTML 下载和文本提取

    下载 URL 列表并仅提取文本内容的好工具或工具集是什么 不需要蜘蛛 但可以控制下载文件名 并且线程将是一个额外的好处 平台是linux wget http linux die net man 1 wget html2ascii http
  • 创建 CA 证书的 x.509 V3 扩展基本约束和密钥用法有什么区别?

    这两个动作似乎做了同样的事情 使用基本约束X 509 证书中的扩展名以表明它是 CA 证书 并且 使用按键用法扩展名例如表示公钥可用于证书签名 这些扩展有什么区别 它们是否有相同的目的或相辅相成 密钥用法 定义了可以使用证书中包含的密钥执行
  • Postgres pg_dump 缓存查找索引失败

    我正在尝试使用以下命令创建 postgres 数据库的备份 省略详细信息 pg dump h host p 5432 U user db gt db sql 一段时间后 我收到错误 已格式化 pg dump archiver db quer
  • 启动期间生成的 ELF 可执行文件段错误

    我正在生成一个 ELF 可执行文件 并将 text 部分加载到 LOAD 段中 它可以很好地拆卸 但尝试在下面运行它gdb gives During startup program terminated with signal SIGSEG
  • 如何在CSS中设置超细“font-weight”(小于100)?

    我想让文字超细 小于 font weight 100 这可以用 CSS 来做吗 Like this but with helvetica 处理 Web 字体时 CSS 字体粗细不会 使字体变细 或加粗 对于未从 url 加载的字体font
  • XML 序列化问题 - 如何序列化一个对象中的元素、属性和文本

    我是使用 NET 进行 XML 序列化的新手 在使用它一段时间后 我现在感到很困惑 我可以序列化具有包含其他元素的属性的元素 但如何序列化类似的内容
  • lodash:使用不同的对象数组过滤对象数组

    这个问题具体针对lodash https lodash com docs 给定两个对象数组 什么是best way用另一个数组的对象过滤一个数组 我试图提出下面的一个场景 我这样做的方法是使用两个 forEach循环 但我想知道使用 lod
  • 在 C# 中根据引用的 XSD 验证 XML

    我有一个具有指定架构位置的 XML 文件 如下所示 xsi schemaLocation someurl localSchemaPath xsd 我想用 C 进行验证 当我打开文件时 Visual Studio 会根据架构验证它并完美列出错
  • SAM 无需重建即可运行

    我已经开始使用AWS SAM for python 在本地测试我的功能时 我运行 sam build use container sam local start api You can now browse to the above end
  • 支持词法范围 ScriptBlock 参数(例如Where-Object)

    考虑以下任意函数和测试用例 Function Foo MyBar Param Parameter Mandatory false ScriptBlock Filter if Filter Filter true Filter Filter