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


about_Scopes

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

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

Подробное описание

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

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

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

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

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

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

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

Примечание.

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

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

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

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

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

Get-Variable -Scope local

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

Get-Variable -Scope global

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

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

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

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

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

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

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

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

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

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

    Примечание.

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

  • script:— указывает, что имя существует в области скрипта. Область скрипта — это ближайшая область файла скрипта предка или глобальная , если нет ближайшего файла скрипта предка.

  • using: — используется для доступа к переменным, определенным в другой области при выполнении скриптов с помощью командлетов, таких как Start-Job и Invoke-Command.

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

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

    Пространство имен Description
    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.

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

Дополнительные сведения см. в следующих разделах:

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

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

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

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

Параметр AllScope

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

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

Управление областью

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

Get-Help * -Parameter scope

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

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

Get-Variable -Scope local

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

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

Для указания области можно также использовать параметр New-AliasSet-Alias"Область" или Get-Alias командлетов. Следующая команда создает псевдоним в глобальной области:

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

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

Примечание.

Для командлетов, использующих параметр Scope , можно также ссылаться на области по числу. Число описывает относительную позицию одной области к другой. Область 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

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

$a = Hello
$global:a = Goodbye

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

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

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

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

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

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

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

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

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

Visibility

Свойство Видимости переменной или псевдонима определяет, отображается ли элемент за пределами контейнера, в котором он был создан. Контейнер может быть модулем, скриптом или оснасткой. Видимость предназначена для контейнеров так же, как 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: модификатора области или путем создания переменной с заданным Privateсвойством Option. Частные переменные можно просматривать или изменять только в области, в которой они были созданы.

В этом примере 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.

См. также