Когда вы пишете сценарий PowerShell без функций и внешних зависимостей от других сценариев, понятие областей видимости PowerShell не вызывает много беспокойства. Понятие глобальных переменных PowerShell не стоит на переднем плане. Но по мере того как вы начинаете создавать функции, модули и учитесь вызывать сценарии из других сценариев, эта тема становится более важной.
В этой статье вы получите глубокий урок о том, что такое области видимости в PowerShell, как они работают и как вы можете писать код с учетом областей видимости. К моменту завершения вы будете понимать глобальные переменные PowerShell и гораздо больше!
Области видимости: что-то вроде ведер
Вы когда-нибудь писали сценарий, где вы определяете переменную, а когда проверяете значение этой переменной, оно оказывается другим? Возможно, вы почешете затылок, пытаясь понять, как эта переменная изменилась, когда вы явно ее определили. Одной из причин может быть то, что значение переменной перезаписывается в другой области видимости.
Возможно, вы задавались вопросом, почему определенные переменные PowerShell имеют значения, когда вы обращаетесь к ним в консоли, но не существуют в ваших сценариях. Вероятно, эти переменные находятся в другом “ведре”, которое в данный момент недоступно.
Области видимости похожи на ведра. Области видимости влияют на то, как PowerShell изолирует переменные, псевдонимы, функции и PSDrives между разными областями. Область видимости похожа на ведро. Это место, где собираются все эти элементы вместе.
Когда PowerShell запускается, он автоматически создает для вас эти “ведра”. На этом этапе вы уже используете области видимости, не осознавая этого. Все области видимости определяются PowerShell и создаются без вашей помощи.
Типы областей видимости
Когда запускается PowerShell, он автоматически создает четыре “ведра” или области видимости, в которые различные элементы могут быть помещены. Вы не можете создавать области видимости самостоятельно. Вы можете только добавлять и удалять элементы из этих областей видимости, определенных ниже.
Глобальная область видимости
Элементы, определенные при открытии PowerShell, устанавливаются в глобальной области видимости. Сюда входят объекты, созданные системой, такие как диски PowerShell, а также все, что вы определили в профиле PowerShell, поскольку ваш профиль запускается при старте.
Элементы в глобальной области видимости доступны везде. Вы можете ссылаться на элементы в глобальной области видимости интерактивно в консоли, в любом скрипте, который вы запускаете, и в любой функции. Глобальные переменные PowerShell вездесущи. По этой причине общее использование глобальных переменных PowerShell заключается в использовании глобальных переменных PowerShell между скриптами.
Существует только одна общая глобальная область видимости.
Область видимости сценария
A script scope is automatically created every time a PowerShell script runs. You can have many different script scope instances. Script scopes are created when you execute a PS1 script or a module, for example.
Только элементы, созданные в определенной области видимости этого сценария, могут ссылаться друг на друга.
Частная область видимости
Обычно элемент, определенный, может быть доступен из других областей видимости – это не верно для элементов в частной области видимости. Элементы в частной области видимости содержат объекты, скрытые от других областей видимости. Частная область видимости используется для создания элементов с тем же именем, что и элементы в других областях видимости, чтобы предотвратить перекрытие.
Локальная область видимости
В отличие от других областей видимости, локальная область видимости немного отличается. Локальная область видимости является указателем на глобальную, скриптовую или частную область видимости. Локальная область видимости относительна контекста, в котором в данный момент выполняется код.
Если вы создаете переменную, псевдоним, функцию или PSDrive без явного присвоения ей области видимости (о чем мы поговорим позже), она будет помещена в локальную область видимости.
Ссылка на области видимости
Теперь, когда у вас есть представление о четырех типах существующих областей видимости, вы также должны знать, что есть два способа ссылаться на эти области.
В PowerShell есть два способа ссылаться на области видимости – по именам или по номерам. Оба метода ссылки используют одни и те же области видимости, но просто в разном виде. Это два различных способа взаимодействия с областями видимости.
Области видимости по именам
Вы уже узнали о областях видимости, ссылка на которые производится по имени. Ссылка на область видимости по имени, интуитивно понятно, называется областью видимости по имени. Основная цель ссылки на область видимости по имени – присвоение элемента области видимости. Как это делается, вы узнаете далее.
Области видимости по номерам
Кроме имени, каждая область видимости имеет номер, начиная с нуля, который всегда будет локальной областью видимости. Области видимости нумеруются динамически относительно текущей локальной области видимости.
Например, как только вы открываете сеанс PowerShell, вы работаете в глобальной области видимости. На этом этапе глобальная область видимости является локальной областью видимости (помните, что локальная область видимости всего лишь указатель).
Поскольку локальная область видимости всегда имеет номер ноль, в настоящее время глобальная область видимости также является областью видимости ноль. Однако, когда вы запускаете сценарий из той же сессии, создается область видимости сценария. При запуске указатель локальной области видимости затем изменяется на область видимости сценария. Теперь область видимости сценария – это область видимости ноль, а глобальная область видимости – область видимости один.
Области видимости нумеруются Этот процесс повторяется для стольких областей видимости, сколько у вас есть, где локальная область видимости равна 0. Области видимости динамически нумеруются по иерархии областей видимости.
Иерархия областей видимости и наследование
Как уже упоминалось ранее, при запуске сеанса PowerShell PowerShell создает для вас некоторые элементы в глобальной области видимости. Эти элементы могут быть функциями, переменными, псевдонимами или PSDrive. Все, что вы определяете в своем сеансе PowerShell, также будет определено в глобальной области видимости.
Поскольку по умолчанию вы находитесь в глобальной области видимости, если вы что-то делаете, что создает другую область видимости, например, выполняете сценарий или запускаете функцию, будет создана дочерняя область видимости, а родительская область будет глобальной областью видимости. Области видимости похожи на процессы с родителями и детьми.
Все, что определено в родительской области видимости, в данном случае в глобальной области видимости, будет доступно в дочерней области видимости. Но эти элементы можно редактировать только в области видимости, в которой они были определены.
Допустим, у вас есть сценарий с именем Test.ps1. Внутри этого сценария есть одна строка, как показано ниже.
Когда вы запускаете этот сценарий, $a
присваивается значение в локальной области видимости (во время выполнения сценария). Когда запускается Test.ps1, вы можете видеть, что после выполнения сценария невозможно ссылаться на него. Поскольку $a
было присвоено в области видимости сценария, область видимости глобальной области (в интерактивной консоли) не может его видеть.

Давайте поднимем этот пример на новый уровень и сделаем сценарий Test.ps1 следующим образом. Теперь сценарий пытается вывести значение $a
перед установкой его в той же области видимости.
Для демонстрации присвойте значение $a
в интерактивной консоли. Это присваивает значение в глобальной области видимости. Теперь, когда сценарий выполняется, он будет наследовать родительскую область видимости (глобальную) и должен видеть значение.
Вы можете видеть, что при выполнении Test.ps1 (создание дочерней области видимости глобальной области) она видит значение $a
. Вы также можете видеть, что значение переменной доступно также и в глобальной области видимости, поскольку именно здесь оно было установлено. Это означает, что $a
доступно как в сценарии (дочерней), так и в родительской (глобальной) областях видимости.

Помните об этом поведении наследования области видимости. Это поможет вам при устранении неудач, таких как конфликты переменных, когда переменные с одинаковым именем находятся в разных областях видимости.
Определение и доступ к элементам в областях видимости
Теперь, когда вы знаете, что такое область видимости и как они работают, как к ним обращаться? Давайте посмотрим, как использовать PowerShell для установки области переменной (и к ним доступа).
Get/Set-Variable
В PowerShell существует две командлеты, позволяющие устанавливать переменные – Get-Variable
и Set-Variable
. Эти командлеты позволяют вам получить значение переменной или задать значение.
Оба командлета похожи с параметрами Name
и Scope
. Используя эти параметры, PowerShell позволяет устанавливать и извлекать значения переменных во всех областях видимости.
Локальные области
Чтобы установить переменную в локальной области, используйте Set-Variable
и укажите имя локальной переменной и значение, как показано ниже.
Локальная область всегда является областью видимости по умолчанию, поэтому не использование параметра Scope
всегда будет определять переменную в локальной области.
Чтобы получить значение переменной с локальной областью, используйте Get-Variable
, предоставив ему имя.
Приватные/Сценарий/Глобальные области
Вы будете использовать те же параметры (Name
и Value
), работая с приватными, сценарными и глобальными переменными. Единственное отличие в том, что на этот раз вы будете использовать параметр Scope, чтобы явно определить область видимости.
Методы установки приватной, сценарной или глобальной переменной такие же. Просто замените значение, переданное параметру Scope
, как Private
, Script
, Global
.
Чтобы получить значение скрипта или переменной с глобальной областью видимости, используйте Get-Variable
, указав имя и область видимости.
Примечание: Вы также можете ссылаться на области с помощью номеров областей вместо имен с помощью командлетов
Get
/Set-Variable
.
Префиксирование области
Вы также можете получать и устанавливать переменные в областях с помощью ярлыка. Вместо использования командлетов PowerShell вы добавите префикс области к переменной при ее ссылке.
Локальные области
Поскольку локальная область всегда является областью по умолчанию, просто определение переменной и ссылка на нее установит и получит переменную локальной области
Приватные/Скриптовые/Глобальные области
Если вы хотите определить и ссылаться на скриптовые или глобальные области, вы можете добавить к переменным имя области и точку с запятой.
Например, чтобы установить переменную $a
в глобальной области, вы можете добавить к a $global:
.
То же самое можно сделать и для переменной, область видимости которой скриптовая.
После того как переменные установлены в предпочтительной области, вы можете ссылаться на них таким же образом. Также обратите внимание, что вы можете исключить префикс области, если определенная область – это локальная область.
Области в блоках скрипта
В PowerShell есть удобная конструкция, называемая блоками скрипта. Блоки скрипта позволяют перемещать фрагменты кода и выполнять их практически в любом месте.
Как и скрипты PS1, блоки скрипта выполняются в своей собственной области видимости скрипта. При выполнении блока скрипта вы по сути выполняете скрипт PS1.
Обратите внимание на пример ниже, где переменная определена в глобальной области видимости, а затем пытается быть перезаписанной в области видимости сценария. Как вы узнали ранее, это не сработает, потому что дочерняя область не может ссылаться на родительскую область.

В этом примере показано, что когда $a
изменяется в блоке сценария, определение переменной global для $a
не изменяется, потому что блок сценария является дочерней областью сценария.
Подключение сценариев (Обмен локальными областями)
В PowerShell существует концепция, называемая подключением сценариев. Этот метод позволяет выполнить сценарий PS1 и принести все, что было бы в области видимости сценария, в локальную область видимости.
Поставив точку (.) перед ссылкой на сценарий PS1 и выполнением его, происходит “подключение” содержимого сценария и принесение всего в локальную область видимости.
Чтобы продемонстрировать, у меня есть снова сценарий Test.ps1, который определяет переменную, как показано ниже.
В консоли PowerShell установите значение переменной $a
, а затем подключите этот сценарий, как показано ниже. Обратите внимание, что исходная переменная была перезаписана. PowerShell “слил” две локальные области вместе.

Использование свойства AllScope (Опция)
Вы видели, как взаимодействовать с элементами в конкретных областях видимости, но до сих пор каждый элемент все равно определен в одной области видимости. Но что, если вы не знаете, в какой области определена переменная?
При определении переменной с помощью командлета Set-Variable
вы можете разместить переменную во всех областях сразу. Для этого используйте значение AllScope
для параметра Option
.
Для демонстрации скрипт Test.ps1 был изменен для установки переменной во всех областях. Эта переменная затем выводится, как показано ниже.
Затем можно увидеть, что значение устанавливается для $a
в глобальной области и выполняется скрипт Test.ps1. Однако вместо того, чтобы не иметь никакого эффекта, значение $a
было перезаписано. Оно было определено не только в области скрипта (Write-Output $a
), но также перезаписало глобальную область.

Параметр AllScope
удобен, но будьте осторожны. Этот параметр фактически устраняет концепцию областей и объединяет все вместе.
Области функций
При выполнении функции весь код внутри этой функции находится в своей собственной дочерней области. Области функций следуют тому же принципу дочерних/родительских областей, что и другие области.
Иметь отдельные области для каждой функции – это хорошая идея. Это позволяет лучше контролировать элементы, не беспокоясь о конфликтах элементов, а также предоставляет дополнительное преимущество автоматической очистки переменных в функции. Как только функция завершается, все элементы, определенные в функции, будут очищены.
Для демонстрации скопируйте/вставьте функцию непосредственно в консоль PowerShell.
После вставки выполните функцию. Обратите внимание, что вы не можете получить доступ к переменной $var
за пределами функции.
Сохранение элементов в частном доступе (отключение наследования)
Обычно, если переменная определена в родительской области видимости, она также будет определена в дочерней области видимости. Но, возможно, вы хотели бы использовать имя переменной, которое уже определено в одной из областей для выполнения в сеансе. В таком случае вы можете выбрать другое имя переменной или определить переменную в частной области видимости, сделав ее частной.
A way to use scopes to reduce conflicts is to use the private scope. Using the private scope disables inheritance on that specific variable. When multiple child scopes are created, those child scopes will not see any variables defined in a private scope.
A Test.ps1 script outputs the value of $a as shown below.
Ниже вы можете видеть, что я определяю переменную с областью видимости только для глобальной области и затем выполняю сценарий Test.ps1. Как правило, при определении переменной в родительской области видимости она будет доступна в дочерней области видимости, но не в случае с переменной с частной областью видимости.
В приведенном ниже примере видно, что созданная дочерняя область видимости сценария, выполняющего сценарий Test.ps1, не могла видеть переменную $a
с частной областью видимости, определенную в родительской области видимости.

В отличие от глобальных областей видимости или опции AllScope
в командлете Set-Variable
, переменные с частной областью видимости – отличный способ компартментализации элементов.
Лучшие практики по области видимости
Думать, что определение переменных в глобальной области видимости или использование опции AllScope
– это правильный путь, довольно распространено. В конце концов, все переменные доступны везде. Нет необходимости беспокоиться о сложностях областей видимости. Хотя это действительно обеспечивает дополнительную свободу доступа к определенным вещам, это может быстро выйти из-под контроля и стать трудным для устранения неполадок.
Вместо того чтобы пытаться избегать использования областей видимости, следуйте этим советам:
- Вместо указания областей видимости в функциях используйте параметры для передачи необходимой информации в функцию.
- Оставайтесь в локальной области видимости насколько это возможно.
- Вместо того чтобы определять глобальные переменные из сценария, используйте командлет
Write-Output
для вывода всего и сохранения его в переменную при необходимости из консоли.
Основная идея здесь – принять области видимости и научиться использовать их в своих интересах, а не пытаться обойти их.