Поделиться через


about_Scopes

Краткое описание

Объясняет концепцию области в PowerShell и показывает, как задать и изменить область элементов.

Длинное описание

PowerShell защищает доступ к переменным, псевдонимам, функциям и дискам PowerShell (PSDrives), ограничивая возможность чтения и изменения. PowerShell использует правила области, чтобы гарантировать, что непреднамеренные изменения элементов в других областях не вносятся.

Правила области

При запуске PowerShell хост (pwsh.exe) создает пространство выполнения PowerShell. Процессы узла могут иметь несколько пространств выполнения. Каждое пространство выполнения имеет собственное состояние сеанса и контейнеры области видимости. Невозможно получить доступ к состоянию сеанса и областям в разных экземплярах пространства выполнения.

Ниже приведены основные правила охвата.

  • Области могут вкладываться. Внешняя область называется родительской областью. Все вложенные области видимости являются дочерними областями родительской области видимости.
  • Элемент отображается в той области, в которой создан, и в любых дочерних областях, если только вы явно не сделаете его приватным.
  • С помощью модификаторов области можно объявлять переменные, псевдонимы, функции и диски PowerShell для области вне текущей области.
  • Элемент, созданный в области, можно изменить только в области, в которой она была создана, если только явно не указать другую область.
  • Если код, выполняющийся в пространстве выполнения, ссылается на элемент, PowerShell выполняет поиск в иерархии областей, начиная с текущей области и переходя через каждую родительскую область.
    • Если элемент не найден, в текущей области создается новый элемент.
    • Если он находит совпадение, значение элемента извлекается из области, где оно было найдено.
    • При изменении значения элемент копируется в текущую область, чтобы изменение влияло только на текущую область.
  • Если вы явно создаете элемент, который делится своим именем с элементом в другой области, исходный элемент может быть скрыт новым элементом, но он не переопределяется или не изменяется.

Родительские и дочерние области

Вы можете создать новую дочернюю область, вызвав скрипт или функцию. Область вызова — это родительская область. Вызываемая скрипт или функция является дочерней областью. Вызываемые функции или скрипты могут вызывать другие функции, создавая иерархию дочерних областей, корневая область которой является глобальной областью.

Заметка

Функции из модуля не выполняются в дочерней области вызывающей области. Модули имеют собственное состояние сеанса, связанное с областью импорта модуля. Весь код модуля выполняется в иерархии областей, которые имеют собственную корневую область. Дополнительные сведения см. в разделе Модули этой статьи.

При создании дочерней области она включает все псевдонимы и переменные, имеющие параметр AllScope и некоторые автоматические переменные. Этот параметр рассматривается далее в этой статье.

Если вы явно не делаете элементы закрытыми, элементы в родительской области доступны дочерней области. Элементы, создаваемые или изменяемые в дочерней области, не влияют на родительскую область, если при создании элементов явно не указывается область.

Чтобы найти элементы в определенной области, используйте параметр Scope Get-Variable или Get-Alias.

Например, чтобы получить все переменные в локальной области, введите:

Get-Variable -Scope Local

Чтобы получить все переменные в глобальной области, введите:

Get-Variable -Scope Global

При создании ссылки на переменную, псевдоним или функцию PowerShell выполняет поиск в текущей области. Если элемент не найден, выполняется поиск родительской области. Этот поиск повторяется вплоть до самой глобальной области. Если переменная является частной в родительской области, поиск продолжается через цепочку областей. Примере 4 показан эффект приватной переменной в процессе поиска области видимости.

Имена областей PowerShell

PowerShell определяет имена для некоторых областей, чтобы упростить доступ к этой области. PowerShell определяет следующие именованные области:

  • Глобальная область: область, которая действует при запуске PowerShell или при создании нового сеанса или пространства выполнения. Переменные и функции, которые присутствуют при запуске PowerShell, такие как автоматические переменные и переменные предпочтения, создаются в глобальной области. Переменные, псевдонимы и функции в профилях PowerShell также создаются в глобальной области. Глобальная область — это корневая родительская область в runspace.
  • Область: текущая область. Локальная область может быть глобальной или любой другой областью.
  • скрипт: область, созданная во время выполнения файла скрипта. Команды в скрипте выполняются в области видимости скрипта. Для команд в скрипте область скрипта — это локальная область.

Для командлетов, поддерживающих области, области могут обозначаться числом, описывающим относительное положение одной области по отношению к другой. Область видимости 0 обозначает текущую (локальную) область видимости, область видимости 1 является родительской по отношению к текущей области видимости, область видимости 2 является областью видимости на два уровня выше текущей. Этот шаблон продолжается до тех пор, пока не будет достигнута корневая область.

Модификаторы области

Переменная, псевдоним или имя функции может включать любой из следующих дополнительных модификаторов области:

  • Global: указывает, что имя существует в глобальной области .

  • Local: — указывает, что имя существует в области Local. Текущая область всегда является локальной областью . При использовании Local: модификатора области PowerShell не выполняет поиск родительских областей. Если элемент существует в текущей области, он используется. Если элемент не существует в текущей области, PowerShell создает новый элемент в текущей области.

  • Private: — определяет, что имя является частным и видимо только для текущей области.

    Заметка

    Private: не является областью видимости. Это параметр , который изменяет доступность элемента вне области, в которой она определена.

  • Script:. Указывает, что имя существует в области скрипта. область скрипта является областью ближайшего родительского файла скрипта или Глобальной, если ближайшего родительского файла скрипта не существует.

  • Using:. Используется для доступа к переменным, определенным в другой области при выполнении в удаленных сеансах, фоновых заданиях или заданиях потока.

  • Workflow: — указывает, что имя существует в рабочем процессе. Примечание. Рабочие процессы не поддерживаются в PowerShell версии 6 и более поздних версиях.

  • <variable-namespace> — модификатор, созданный поставщиком PSDrive PowerShell. Например:

    Пространство имен Описание
    Alias: Псевдонимы, определенные в текущей области
    Env: Переменные среды, определенные в текущем контексте
    Function: Функции, определенные в текущей области
    Variable: Переменные, определенные в текущей области

Область по умолчанию для скриптов — это область скрипта. Область по умолчанию для функций и псевдонимов — это локальная область, даже если они определены в скрипте.

Использование модификаторов области

Чтобы указать область новой переменной, псевдонима или функции, используйте модификатор области.

Синтаксис модификатора области в переменной:

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

Синтаксис модификатора области в функции:

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

С помощью следующей команды, которая не использует модификатор области, создается переменная в текущей или локальной области.

$a = "one"

Чтобы создать ту же переменную в области глобальной, используйте модификатор области Global::

$Global:a = "one"
Get-Variable a | Format-List *

Обратите внимание на значения свойств видимости и параметров.

Name        : a
Description :
Value       : one
Visibility  : Public
Module      :
ModuleName  :
Options     : None
Attributes  : {}

Сравните это с частной переменной:

$Private:pVar = 'Private variable'
Get-Variable pVar | Format-List *

Использование модификатора области Private: задает для свойства Options значение Private.

Name        : pVar
Description :
Value       : Private variable
Visibility  : Public
Module      :
ModuleName  :
Options     : Private
Attributes  : {}

Чтобы создать ту же переменную в области скрипта, используйте модификатор области Script::

$Script:a = "one"

Можно также использовать модификатор области с функциями. Следующее определение функции создает функцию в глобальной области :

function Global:Hello {
  Write-Host "Hello, World"
}

Можно также использовать модификаторы области для ссылки на переменную в другой области. Следующая команда ссылается на переменную $test, сначала в локальной области, а затем в глобальной области:

$test
$Global:test

Модификатор области Using:

Использование — это специальный модификатор области, идентифицирующий локальную переменную в удаленной команде. Без модификатора PowerShell ожидает, что переменные в удаленных командах будут определены в удаленном сеансе.

Модификатор области Using: появился в PowerShell 3.0.

Для любого скрипта или команды, выполняющегося вне сеанса, требуется модификатор области Using: для внедрения значений переменных из области вызывающего сеанса, чтобы получить к ним доступ из кода сеанса. Модификатор области Using: поддерживается в следующих контекстах:

  • Удаленные команды, запущенные с Invoke-Command с помощью параметров ComputerName, HostName, SSHConnection или Session (удаленный сеанс)
  • Фоновые задания, запущенные с Start-Job (внепроцессный сеанс)
  • Задания потоков, запущенные с помощью Start-ThreadJob или ForEach-Object -Parallel (отдельный сеанс потока)

В зависимости от контекста внедренные значения переменных представляют собой независимые копии данных в области вызывающего объекта или ссылки на него. В удаленных и внепроцессных сеансах это всегда независимые копии.

Дополнительные сведения см. в about_Remote_Variables.

Ссылка $Using: расширяется только на значение переменной. Если вы хотите изменить значение переменной в области вызывающего объекта, необходимо иметь ссылку на саму переменную. Вы можете создать ссылку на переменную, получив экземпляр PSVariable. В следующем примере показано, как создать ссылку и внести изменения в потоковую задачу.

$Count = 1
$refOfCount = Get-Variable Count

Start-ThreadJob {
    ($Using:refOfCount).Value = 2
} | Receive-Job -Wait -AutoRemoveJob

$Count
2

Заметка

Эта операция не является потокобезопасной. Если вы пытаетесь одновременно изменить значение из нескольких потоков, можно привести к повреждению данных. Для защиты общих данных следует использовать потокобезопасные типы данных или примитивы синхронизации. Дополнительные сведения см. в коллекциях Thread-Safe.

Сериализация значений переменных

Удаленные команды и фоновые задания выполняются вне процесса. Сеансы вне процесса используют сериализацию и десериализацию на основе XML, чтобы сделать значения переменных доступными в границах процесса. Процесс сериализации преобразует объекты в PSObject, содержащий исходные свойства объектов, но не его методы.

Для ограниченного набора типов десериализация восстанавливает объекты обратно в исходный тип. Регидратированный объект является копией исходного экземпляра объекта. Он имеет типовые свойства и методы. Для простых типов, таких как System.Version, копия является точной. Для сложных типов копия несовершенна. Например, гидратированные объекты сертификатов не включают закрытый ключ.

Экземпляры всех остальных типов являются экземплярами PSObject. Свойство pstypenames содержит префикс имени исходного типа с префиксом десериализации, например Deserialized.System.Data.DataTable

Опция AllScope

Переменные и псевдонимы имеют свойство Option, которое может принимать значение AllScope. Элементы, имеющие свойство AllScope, становятся частью любых создаваемых дочерних областей, хотя они не наследуются задним числом родительскими областями.

Элемент, имеющий свойство AllScope, отображается в дочерней области и является её частью. Изменения элемента в любой области влияют на все области, в которых определена переменная.

Управление объёмом работ

Несколько командлетов имеют параметр Области, который позволяет получать или задавать (создавать и изменять) элементы в определенной области. Используйте следующую команду, чтобы найти все командлеты в сеансе с параметром области :

Get-Help * -Parameter Scope

Чтобы найти переменные, видимые в определенной области, используйте параметр ScopeGet-Variable. Видимые переменные включают глобальные переменные, переменные в родительской области и переменные в текущей области.

Например, следующая команда получает переменные, видимые в локальной области:

Get-Variable -Scope Local

Чтобы создать переменную в определенной области, используйте модификатор области или параметр ScopeSet-Variable. Следующая команда создает переменную в глобальной области:

New-Variable -Scope Global -Name a -Value "One"

Вы также можете использовать параметр Scope командлетов New-Alias, Set-Aliasили Get-Alias для указания области. Следующая команда создает псевдоним в глобальной области:

New-Alias -Scope Global -Name np -Value Notepad.exe

Чтобы получить функции в определенной области, используйте командлет Get-Item, находясь в этой области. Командлет Get-Item не имеет параметра области .

Заметка

Для командлетов, использующих параметр области , можно также ссылаться на области по номеру. Число описывает относительную позицию одной области к другой. Область 0 представляет текущую или локальную область. Область 1 указывает немедленную родительскую область. Сфера 2 обозначает родителя родительской сферы и так далее. Нумерованные области полезны, если вы создали множество рекурсивных областей.

Использование нотации dot-source с областью

Скрипты и функции соответствуют правилам области. Вы создаете их в определенной области, и они влияют только на эту область, если вы не используете параметр командлета или модификатор области для изменения этой области.

Но вы можете добавить содержимое скрипта или функции в текущую область с помощью нотации dot-source. При запуске скрипта или функции с использованием нотации dot-source он выполняется в текущей области. Все функции, псевдонимы и переменные в скрипте или функции добавляются в текущую область.

Например, чтобы запустить скрипт Sample.ps1 из каталога C:\Scripts в области скрипта (по умолчанию для скриптов), просто введите полный путь к файлу скрипта в командной строке.

C:\scripts\sample.ps1

Файл скрипта должен иметь расширение .ps1, чтобы быть исполняемым. Файлы с пробелами в пути должны быть заключены в кавычки. При попытке выполнить путь в кавычках, PowerShell отображает содержимое этой строки в кавычках вместо запуска скрипта. Оператор вызова (&) позволяет выполнять содержимое строки, содержащей имя файла.

Использование оператора вызова для запуска функции или скрипта выполняет ее в области скрипта. Использование оператора вызова не отличается от запуска скрипта по имени.

& C:\scripts\sample.ps1

Дополнительные сведения об операторе вызова см. в about_Operators.

Чтобы запустить скрипт Sample.ps1 в локальной области, введите точку и пробел (. ) перед путем к скрипту:

. C:\scripts\sample.ps1

Теперь все функции, псевдонимы или переменные, определенные в скрипте, добавляются в текущую область.

Ограничение без области

PowerShell имеет некоторые параметры и функции, аналогичны понятию области, и может взаимодействовать с областями. Эти функции могут быть спутаны с областью или поведением области.

Сеансы, модули и вложенные запросы — это автономные среды, а не дочерние области глобальной области в сеансе.

Сеансы

Сеанс — это среда, в которой выполняется PowerShell. При создании сеанса на удаленном компьютере PowerShell устанавливает постоянное подключение к удаленному компьютеру. Постоянное подключение позволяет использовать сеанс для нескольких связанных команд.

Так как сеанс является ограниченной средой, он имеет собственную область, но не является дочерней областью сеанса, в котором был создан. Сеанс начинается с собственной глобальной области. Эта область не зависит от глобальной области сеанса. В сеансе можно создать дочерние области. Например, можно запустить скрипт для создания дочерней области в сеансе.

Модули

Модуль PowerShell можно использовать для совместного использования и доставки инструментов PowerShell. Модуль — это единица, которая может содержать командлеты, скрипты, функции, переменные, псевдонимы и другие полезные элементы. Если элементы модуля явно не экспортированы (с помощью Export-ModuleMember или манифеста модуля), они недоступны за пределами модуля. Поэтому модуль можно добавить в сеанс и использовать общедоступные элементы, не беспокоясь о том, что иные элементы могли бы переопределить командлеты, скрипты, функции и другие элементы в сеансе.

По умолчанию модули загружаются в область корневого уровня (глобального) пространства выполнения. Импорт модуля не изменяет область. В сеансе модули имеют собственную область. Рассмотрим следующий модуль C:\temp\mod1.psm1:

$a = "Hello"

function foo {
    "`$a = $a"
    "`$Global:a = $Global:a"
}

Теперь мы создадим глобальную переменную $a, присвойте ей значение и вызовите функцию foo.

$a = "Goodbye"
foo

Модуль объявляет переменную $a в области модуля, а функция foo выводит значение переменной в обеих областях.

$a = Hello
$Global:a = Goodbye

Модули создают контейнеры параллельной области, связанные с областью, в которой они были импортированы. Элементы, экспортированные модулем, доступны начиная с уровня области, в котором они импортируются. Элементы, не экспортированные из модуля, доступны только в контейнере области модуля. Функции в модуле могут получить доступ к элементам в области, в которой они были импортированы, а также к элементам в области контейнера модуля.

Если вы загружаете Module2 из вModule1, Module2 загружается в контейнер области Module1. Все экспорты из модуля Module2 помещаются в текущую область модуля module1. При использовании Import-Module -Scope Localэкспорт помещается в текущий объект области, а не на верхнем уровне. Если вы в модуле и загружаете другой модуль с помощью Import-Module -Scope Global (или Import-Module -Global), этот модуль и его экспорт загружаются в глобальную область вместо локальной области модуля. Функция WindowsCompatibility делает это для импорта проксируемых модулей в глобальное состояние сеанса.

Вложенные запросы

Вложенные запросы не имеют собственного контекста. Когда вы вводите вложенный запрос, то вложенный запрос является подмножеством среды. Но вы остаетесь в пределах локальной области видимости.

Скрипты имеют собственную область видимости. Если вы выполняете отладку скрипта и достигнете точки останова в скрипте, введите область скрипта.

Приватный параметр

Псевдонимы и переменные имеют свойство Option, которое может принимать значение Private. Элементы с параметром Private можно просматривать и изменять в области, в которой они созданы, но их нельзя просматривать или изменять вне этой области.

Например, если вы создаете переменную с частным параметром в глобальной области, а затем запускаете скрипт, Get-Variable команды в скрипте не отображают частную переменную. Использование модификатора области Global: в этом экземпляре не отображает частную переменную.

Параметр в параметре для New-Variable, Set-Variable, New-Aliasи командлета Set-Alias можно использовать для установки значения свойства Option на Private.

Видимость

Свойство Видимости переменной или псевдонима определяет, можно ли видеть элемент за пределами контейнера, в котором он был создан. Контейнер может быть модулем, скриптом или надстройкой. Видимость предназначена для контейнеров так же, как и значение Private свойства Option предназначено для областей.

Свойство видимости принимает значения Public и Private. Элементы, имеющие частную видимость, можно просматривать и изменять только в контейнере, в котором они были созданы. Если контейнер добавляется или импортируется, элементы, имеющие частную видимость, нельзя просматривать или изменять.

Поскольку видимость предназначена для контейнеров, в рамках области видимости она работает иначе.

  • Если вы создаете элемент с частной видимостью в глобальной области, вы не можете просматривать или изменять элемент в какой-либо области.
  • Если вы пытаетесь просмотреть или изменить значение переменной с частной видимостью, PowerShell возвращает сообщение об ошибке.

С помощью командлетов New-Variable и Set-Variable можно создать переменную с частной видимостью.

Примеры

Пример 1. Изменение значения переменной только в скрипте

Следующая команда изменяет значение переменной $ConfirmPreference в скрипте. Изменение не влияет на глобальную область.

Во-первых, чтобы отобразить значение переменной $ConfirmPreference в локальной области, используйте следующую команду:

PS>  $ConfirmPreference
High

Создайте скрипт Scope.ps1, содержащий следующие команды:

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

Запустите скрипт. Скрипт изменяет значение переменной $ConfirmPreference, а затем сообщает о его значении в области скрипта. Выходные данные должны выглядеть следующим образом:

The value of $ConfirmPreference is Low.

Затем проверьте текущее значение переменной $ConfirmPreference в текущей области.

PS>  $ConfirmPreference
High

В этом примере показано, что изменения значения переменной в области скрипта не влияют на значение переменной в родительской области.

Пример 2. Просмотр значения переменной в разных областях

Модификаторы области можно использовать для просмотра значения переменной в локальной области и родительской области.

Сначала определите переменную $test в глобальной области.

$test = "Global"

Затем создайте скрипт Sample.ps1, определяющий переменную $test. В скрипте используйте модификатор области для ссылки на глобальные или локальные версии переменной $test.

В 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.

PS> $test
Global

Пример 3. Изменение значения переменной в родительской области

Если вы не защищаете элемент с помощью частного параметра или другого метода, можно просмотреть и изменить значение переменной в родительской области.

Сначала определите переменную $test в глобальной области.

$test = "Global"

Затем создайте скрипт Sample.ps1, определяющий переменную $test. В скрипте используйте модификатор области для ссылки на глобальные или локальные версии переменной $test.

В Sample.ps1:

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

По завершении скрипта глобальное значение $test изменяется.

PS> $test
Local

Пример 4. Создание частной переменной

Переменная может быть закрыта с помощью модификатора области Private: или путем создания переменной с свойством Option, равным Private. Частные переменные можно просматривать или изменять только в области, в которой они были созданы.

В этом примере скрипт ScopeExample.ps1 создает пять функций. Первая функция вызывает следующую функцию, которая создает дочернюю область. Одна из функций имеет частную переменную, которая может быть замечена только в области, в которой она была создана.

PS> Get-Content ScopeExample.ps1
# Start of ScopeExample.ps1
function funcA {
    "Setting `$funcAVar1 to 'Value set in funcA'"
    $funcAVar1 = "Value set in funcA"
    funcB
}

function funcB {
    "In funcB before set -> '$funcAVar1'"
    $Private:funcAVar1 = "Locally overwrite the value - child scopes can't see me!"
    "In funcB after set  -> '$funcAVar1'"
    funcC
}

function funcC {
    "In funcC before set -> '$funcAVar1' - should be the value set in funcA"
    $funcAVar1 = "Value set in funcC - Child scopes can see this change."
    "In funcC after set  -> '$funcAVar1'"
    funcD
}

function funcD {
    "In funcD before set -> '$funcAVar1' - should be the value from funcC."
    $funcAVar1 = "Value set in funcD"
    "In funcD after set  -> '$funcAVar1'"
    '-------------------'
    ShowScopes
}

function ShowScopes {
    $funcAVar1 = "Value set in ShowScopes"
    "Scope [0] (local)  `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 0 -ValueOnly)'"
    "Scope [1] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 1 -ValueOnly)'"
    "Scope [2] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 2 -ValueOnly)'"
    "Scope [3] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 3 -ValueOnly)'"
    "Scope [4] (parent) `$funcAVar1 = '$(Get-Variable funcAVar1 -Scope 4 -ValueOnly)'"
}
funcA
# End of ScopeExample.ps1
PS> .\ScopeExample.ps1

Выходные данные показывают значение переменной в каждой области. Вы можете увидеть, что приватная переменная видна только в области funcB, в которой она была создана.

Setting $funcAVar1 to 'Value set in funcA'
In funcB before set -> 'Value set in funcA'
In funcB after set  -> 'Locally overwrite the value - child scopes can't see me!'
In funcC before set -> 'Value set in funcA' - should be the value set in funcA
In funcC after set  -> 'Value set in funcC - Child scopes can see this change.'
In funcD before set -> 'Value set in funcC - Child scopes can see this change.' - should be the value from funcC.
In funcD after set  -> 'Value set in funcD'
-------------------
Scope [0] (local)  $funcAVar1 = 'Value set in ShowScopes'
Scope [1] (parent) $funcAVar1 = 'Value set in funcD'
Scope [2] (parent) $funcAVar1 = 'Value set in funcC - Child scopes can see this change.'
Scope [3] (parent) $funcAVar1 = 'Locally overwrite the value - child scopes can't see me!'
Scope [4] (parent) $funcAVar1 = 'Value set in funcA'

Как показано в выходных данных из ShowScopes, можно получить доступ к переменным из других областей с помощью Get-Variable и указания номера области.

Пример 5. Использование локальной переменной в удаленной команде

Для переменных в удаленной команде, созданной в локальном сеансе, используйте модификатор области Using:. PowerShell предполагает, что переменные в удаленных командах были созданы в удаленном сеансе.

Синтаксис:

$Using:<VariableName>

Например, следующие команды создают переменную $Cred в локальном сеансе, а затем используют переменную $Cred в удаленной команде:

$Cred = Get-Credential
Invoke-Command $s {Remove-Item .\Test*.ps1 -Credential $Using:Cred}

Модификатор области Using: появился в PowerShell 3.0.

См. также