关于 Powershell 中的作用域

Yoa*_*ein 6 .net variables powershell scope

我正在学习 Powershell 中的范围并且有一些问题:

  1. 关于“本地范围”:从我读到的内容来看,本地范围始终是当前范围。所以,默认情况下,当我们创建一个项目(没有范围修饰符),例如一个变量,在某个范围内,让它是脚本或全局,范围将相应地是脚本/全局。所以我的问题是:我们什么时候需要明确指定local修饰符?
  2. MSDN 说:

您可以通过运行脚本或函数、创建会话或启动 PowerShell 的新实例来创建新范围。创建新作用域时,结果是父作用域(原始作用域)和子作用域(您创建的作用域)。...
除非您明确将项目设为私有,否则父范围中的项目可用于子范围。但是,您在子作用域中创建和更改的项不会影响父作用域,除非您在创建项时明确指定作用域。

但是当我尝试以下操作时:

PS> $Name = "John"
PS> Powershell.exe
PS>echo $Name  // No Output
Run Code Online (Sandbox Code Playgroud)

从上面的引用看来,“启动一个新的 powershell 实例”是一个子作用域,所以父作用域中的所有项目都应该在那里可见。有人可以解释一下吗?

mkl*_*nt0 2

为了补充iRon 的有用答案

  1. [...]什么时候我们需要显式指定本地修饰符?

$local:很少需要,因为本地作用域是在没有作用域说明符的情况下隐含的。

但是,这只适用于引用的变量实际上作为局部变量存在的情况,因为PowerShell 的动态作用域使祖先(父)作用域中的变量也对后代(子)作用域可见(有关更多信息,请参阅此答案):

  • 例如,假设您已在全局$foo = 'bar'范围内声明,那么在脚本中引用将首先查找本地实例;如果没有,则使用在祖先(父)范围中定义的(如果有的话),在本例中它将是全局的并将被返回。$foo $foo$foo $foo'bar'

  • 相比之下,如果在脚本中使用, 而不定义$local:foo局部变量,则默认情况下会出现这种情况,或者如果或更高版本有效,则会发生语句终止错误。$foo$nullSet-StrictMode -Version 2


  1. MSDN 说:[...] 通过创建会话或启动 PowerShell 的新实例 [...] 结果是父作用域(原始作用域)和子作用域(您创建的作用域)。

截至撰写本文时,文档在这方面不正确(已提交GitHub问题):

  • 范围之间的祖先(父子)关系仅存在于给定会话(运行空间)的上下文中。

    • 也就是说,动态作用域(来自祖先作用域的变量和其他定义的可见性)仅适用于给定会话内的作用域。

    • 一个值得注意的例外是模块中的函数不会在调用作用域的子作用域中运行- 除非该调用作用域恰好是全局作用域;模块有自己的作用域(技术上称为会话状态),仅链接到全局作用域 - 请参阅此 GitHub 文档问题进行讨论。

  • 因此,在以下情况下不会创建调用作用域的子作用域,其中新启动的代码对调用作用域中的变量(和其他定义)一无所知

    • 通过 PowerShell 远程处理启动新会话(例如,使用Enter-PSSession)或Invoke-Command -Computer

    • 在 v7.0+ 中使用或并行运行线程启动后台 [线程] 作业Start-JobStart-ThreadJobForEach-Object -Parallel

    • 使用PowerShell CLI(对于 PowerShell [Core]、对于 Windows PowerShell)启动新的 PowerShell 实例(进程) 。pwshpowershell.exe

    • 在这些场景中,要将值从调用范围传递到新启动的代码,需要显式操作

      • 当调用 CLI 或使用 时(在同一计算机上创建Start-Job进程) ,只有在调用进程中定义的环境变量才会自动可供子进程使用。
      • 否则,来自调用者的值必须作为参数传递,或者 - 除非使用 CLI - 通过$using:作用域 - 请参阅此答案