about_Scopes

主题
    about_Scopes

简短说明
    介绍 Windows PowerShell 中的作用域的概念,并演示如何设置和更改元素的作用域。

    
详细说明
    Windows PowerShell 通过限制可以在哪些位置读取和更改变量、别名、函数和 Windows 
    PowerShell 驱动器 (PSDrive),来保护对它们的访问。通过实施一些简单的作用域规则,
    Windows PowerShell 来帮助确保不会在无意中更改不应更改的项。


    以下为作用域的基本规则:

        - 对于包括在某个作用域中的项,除非您明确将其指定为专用,否则它在创建它的作用域
          及其任何子作用域中都是可见的。可以将变量、别名、函数或 Windows PowerShell 
          驱动器放在一个或多个作用域中。

        - 在作用域中创建的项只能在创建该项的作用域中更改,除非您明确指定了另一个作用域。


    如果在作用域中创建了一个项,该项与另一个作用域中的某个项名称相同,则原始项会隐藏在新项下。
    但是,原始项不会被覆盖或更改。


  Windows PowerShell 作用域

    Windows PowerShell 中的作用域既具有名称也具有编号。有名称的作用域指定一个绝对作用域。编号是相
    对的,并且反映了作用域之间的关系。


    全局:
        在 Windows PowerShell 启动时生效的作用域。当 Windows PowerShell 启动时已经存在一些
        变量和函数,它们都是在全局域中创建的。其中包括自动变量和首选项变量。另外还包括 Windows 
        PowerShell 配置文件中的变量、别名和函数。

    本地:
        当前的作用域。本地作用域可以是全局作用域或任何其他作用域。

    脚本:
        当脚本文件运行时创建的作用域。只有脚本中的命令才在脚本作用域中运行。
        对于脚本中的命令而言,脚本作用域为本地作用域。

    私有:
        在当前作用域之外无法看到私有作用域中的项。可使用私有作用域来创建
        与另一作用域同名的项的私有版本。 

    编号作用域:
        可以按名称或按编号来引用作用域,这些编号描述了某个作用域相对于另一个作用域的位置。
        Scope 0 表示当前作用域(即本地作用域)。Scope 1 表示直属的父作用域。Scope 2 表示
        父作用域的父作用域,依此类推。如果创建了很多递归作用域,则编号作用域就非常有用。


 父作用域和子作用域
 
    可以通过运行脚本或函数、创建会话或启动 Windows PowerShell 的新实例来创建新作用域。创建
    新作用域时,会形成一个父作用域(原始作用域)和一个子作用域(您所创建的作用域)。


    在 Windows PowerShell 中,所有的作用域都是全局作用域的子作用域,但您可以创建很多作用域
    和很多递归作用域。


    除非您将父作用域中的项指定为专用,否则这些项也可用于子作用域。但是,在子作用域中创建和更改的
    项不会影响父作用域,除非您在创建这些项时明确指定了作用域。

    
 继承
 
    子作用域不从父作用域继承变量、别名和函数。子作用域可以查看父作用域中的项,除非这个项是专用的。
    此外,通过明确指定父作用域,子作用域可以更改这些项,但这些项不属于子作用域的一部分。


    但是,在创建子作用域时,它已经包括了一组项。通常,它包括所有具有 AllScope 选项的别名。此
    选项将在本主题后面部分进行讨论。子作用域还包括所有具有 AllScope 选项的变量,以及一些可用于
    自定义作用域的变量(如 MaximumFunctionCount)。


    若要查找特定作用域中的项,请使用 Get-Variable 或 Get-Alias 的 Scope 参数。


    例如,若要获取本地作用域中的所有变量,请键入:

    get-variable -scope local


    若要获取全局作用域中的所有变量,请键入:

    get-variable -scope global


 作用域修饰符
 
    若要指定新的变量、别名或函数的作用域,请使用作用域修饰符。修饰符的有效值是 Global 和 Script。


    变量中的作用域修饰符的语法如下:

        $[<scope-modifier>]:<name> = <value>


    函数中的作用域修饰符的语法如下:

        function [<scope-modifier>]:<name> {<function-body>}


    脚本的默认作用域是脚本作用域。函数和别名的默认作用域是本地作用域,即使它们是在脚本中定义的也不例外。
 
 
    以下命令在当前作用域(即本地作用域)中创建一个变量,而不使用作用域修饰符:

       $a = "one"

 
    若要在全局作用域中创建相同变量,请使用 Global 作用域修饰符:

       $global:a = "one"


    若要在脚本作用域中创建相同变量,请使用 script 作用域修饰符:

       $script:a = "one"


    也可以在函数中使用作用域修饰符。以下函数定义在全局作用域中创建函数:

       function global:Hello
       {
        write-host "Hello, World"
       }


    还可以使用作用域修饰符引用不同作用域中的变量。以下命令引用 $test 变量,首先引用本地作用域
    中的该变量,然后引用全局作用域中的该变量:

      $test
    
      $global:test


 AllScope 选项
 
    变量和别名具有 Option 属性,该属性的取值可以是 AllScope。具有 AllScope 属性的项成为您
    创建的任何子作用域的一部分,但它们不会反过来由父作用域继承。


    具有 AllScope 属性的项在子作用域中是可见的,并且是该作用域的一部分。对任何作用域中的项的
    更改会影响所有定义了该变量的作用域。


 管理作用域
 
    有几个 cmdlet 具有 Scope 参数,您可通过该参数获取或设置(创建和更改)特定作用域中的项。
    使用以下命令可查找会话中所有具有 Scope 参数的 cmdlet:

         get-help * -parameter scope


    若要查找在特定作用域中可见的变量,请使用 Get-Variable 的 Scope 参数。可见参数包括全局参
    数、父作用域中的参数以及当前作用域中的参数。


    例如,以下命令获取本地作用域中可见的变量:

        get-variable -scope local


    若要在特定作用域中创建变量,请使用作用域修饰符或使用 Set-Variable 的 Scope 参数。以下命
    令在全局作用域中创建一个变量:

    new-variable -scope global -name a -value "One"


    也可以使用 New-Alias、Set-Alias 或 Get-Alias cmdlet 的 Scope 参数指定作用域。以下
    命令在全局作用域中创建一个别名:

    new-alias -scope global -name np -value Notepad.exe


    若要获取特定作用域中的函数,请在该作用域中使用 Get-Item cmdlet。Get-Item cmdlet 没有 
    Scope 参数。


 将使用点"."获得来源表示法用于作用域
 
    脚本和函数遵循所有作用域规则。您在特定作用域中创建脚本和函数,除非使用 cmdlet 参数或作用
    域修饰符来更改该作用域,否则这些脚本和函数只会影响该作用域。


    但是,可以使用"使用点'.'获得来源"表示法将脚本或函数添加到当前作用域。然后,当脚本在当前作用
    域中运行时,脚本创建的所有函数、别名和变量在当前作用域中都可用。
 

    若要将函数添加到当前作用域中,请在函数调用中的函数路径和名称之前键入一个圆点 (.) 和一个空格。


    例如,若要在脚本作用域中运行 C:\Scripts 目录下的 Sample.ps1 脚本(脚本的默认值),请使
    用以下命令:

        c:\scripts\sample.ps1


    若要在本地作用域中运行 Sample.ps1 脚本,请使用以下命令:

        . c:\scripts.sample.ps1

   
    使用调用运算符 (&) 运行函数或脚本时,不会将其添加到当前作用域中。下面的示例使用了调用运算
    符:

        & c:\scripts.sample.ps1


    Sample.ps1 脚本创建的所有别名、函数或变量在当前作用域中都不可用。


 不使用作用域进行限制
 
    有一些 Windows PowerShell 概念与作用域非常相似,或者与作用域有共通之处。这些概念可能会
    与作用域或作用域行为混淆。


    会话、模块和嵌套提示是自包含的环境,但它们不是会话中全局作用域的子作用域。


    会话:
        会话是 Windows PowerShell 的运行环境。
        在远程计算机上创建会话时,Windows PowerShell 会建立与远程计算机的持续性连接。通过
        持续性连接,您可以使用会话运行多个相关命令。
 

        由于会话是自包含的环境,因此它具有自己的作用域,但会话并不是创建它的那个会话的子作用域。
        会话在启动时具有自己的全局作用域。此作用域独立于会话的全局作用域。可以在会话中创建子作用域。
        例如,可以在会话中运行一个脚本以创建子作用域。

    模块:
        可以使用 Windows PowerShell 模块共享和传送 Windows PowerShell 工具。模块是一个
        可以包含 cmdlet、脚本、函数、变量、别名和其他有用项的单元。除非明确定义,否则在模块之
        外无法访问模块中的项。因此,您可将模块添加到会话中并使用公用项,而无需担心其他项会重写会
        话中的 cmdlet、脚本、函数和其他项。


        模块的隐私性行为与作用域相似,但将模块添加到会话中不会更改作用域。此外,虽然模块中的脚
        本和所有 Windows PowerShell 脚本一样,也具有自己的作用域,但模块并没有自己的作用域。


    嵌套提示:
        同样,嵌套提示也没有自己的作用域。在进入嵌套提示时,嵌套提示是环境的子集。但您仍然在本地作用域内。


        脚本确实有它们自己的作用域。如果正在对脚本进行调试,当到达脚本中的断点时,则会进入脚本作用域。


    Private 选项:
        别名和变量具有 Option 属性,该属性的取值可以是 Private。具有 Private 选项的项可以
        在创建它们的作用域中查看和更改,但不能在该作用域之外查看和更改。


        例如,如果在全局作用域中创建具有 private 选项的变量,然后运行脚本,则脚本中的 Get-
        Variable 命令不会显示专用变量。即使使用全局作用域修饰符也是如此。
   

        可以使用 New-Variable、Set-Variable、New-Alias 和 Set-Alias cmdlet 的 
        Option 参数将 Option 属性的值设置为 Private。


    Visibility:
        变量或别名的 Visibility 属性决定了您是否可以在创建某个项的容器(例如一个模块)之外看
        到该项。正如 Option 属性的 Private 值是针对作用域设计的那样,Visibility 属性是针对
        容器设计的。


        Visibility 属性的取值可以是 Public 和 Private。Visibility 属性值为 Private 的
        项只能在创建该项的容器中查看和更改。如果容器是添加或导入的,则无法查看或更改 
        Visibility 属性值为 Private 的项。


        由于 Visibility 属性是针对容器设计的,因此它在作用域中的使用方式有所不同。如果在全局
        作用域中创建一个 Visibility 属性值为 Private 的项,则无法在任何作用域中查看或更改该
        项。如果试图查看或更改 Visibility 属性值为 Private 的变量的值,则 Windows 
        PowerShell 会返回错误消息。


        可以使用 New-Variable 和 Set-Variable cmdlet 创建 Visibility 属性值为 
        Private 的变量。

   
示例

  示例 1:仅在脚本中更改变量值

      以下命令在脚本中更改 $ConfirmPreference 变量的值。该更改不会影响全局作用域。

    
      首先,为了显示 $ConfirmPreference 变量在本地作用域中的值,请使用以下命令:

          C:\PS> $ConfirmPreference
          High


      创建包含以下命令的 Scope.ps1 脚本:

          $ConfirmPreference = "Low"
          "The value of `$ConfirmPreference is $ConfirmPreference."

      运行该脚本。该脚本更改 $ConfirmPreference 变量的值,然后报告该变量在脚本作用域中的
      值。输出应该类似于以下输出:

          The value of $ConfirmPreference is Low.

        
      接下来,测试 $ConfirmPreference 变量在当前作用域中的当前值。

          C:\PS> $ConfirmPreference
          High

      
      此示例表明,在脚本作用域中更改某个变量的值不会影响该变量在父作用域中的值。


  示例 2:查看不同作用域中的变量值
      可以使用作用域修饰符查看变量在本地作用域和父作用域中的值。


      首先,在全局作用域中定义 $test 变量。

      $test = "Global"

      接下来,创建定义 $test 变量的 Sample.ps1 脚本。在该脚本中,使用作用域修饰符引用 
      $test 变量的全局或本地版本。


          # In Sample.ps1

          $test = "Local"
          "The local value of `$test is $test." "The global value of 
          `$test is $global:test."
    
      运行 Sample.ps1 时,输出应该类似于以下输出:
         
          The local value of $test is Local.
          The global value of $test is Global.


      脚本完成时,仅在会话中定义了 $test 的全局值。

          C:\PS> $test
          Global


  示例 3:更改变量在父作用域中的值

      除非您使用 Private 选项或其他方法来保护某个项,否则就可以查看和更改变量在父作用域中的值。


      首先,在全局作用域中定义 $test 变量。

      $test = "Global"


      接下来,创建定义 $test 变量的 Sample.ps1 脚本。在该脚本中,使用作用域修饰符引用 
      $test 变量的全局或本地版本。

          # In Sample.ps1

          $global:test = "Local"
          "The global value of `$test is $global:test."

        
      脚本完成时,$test 的全局值已更改。

          C:\PS> $test
          Local
          

  例 4:创建专用变量

      专用变量是 Option 属性值为 Private 的变量。子作用域继承专用变量,但这些变量只能在创建
      它们的作用域中查看或更改。


      以下命令在本地作用域中创建一个名为 $ptest 的专用变量。

      new-variable -name ptest -value 1 -option private


      可以在本地作用域中显示和更改 $ptest 的值。

      C:\PS> $ptest
          1
          C:\PS> $ptest = 2
          C:\PS> $ptest
      2
         
      
      接下来,创建包含以下命令的 Sample.ps1 脚本。
      该命令尝试显示和更改 $ptest 的值。

          # In Sample.ps1

          "The value of `$Ptest is $Ptest."
          "The value of `$Ptest is $global:Ptest."

    
      由于 $ptest 变量在脚本作用域中是不可见的,因此输出为空。
    
          "The value of $Ptest is ."
          "The value of $Ptest is ."
        
   
另请参阅
    about_Variables
    about_Environment_Variables
    about_Functions
    about_Script_Blocks