Хорошая новость: Я не думаю, что функция видимости переменных применима на практике, по крайней мере, не для кода PowerShell, который выполняется в обычном сеансе PowerShell (обычно в консоли (терминале)).
На момент написания этой статьи документация сбивает с толку и кажется несовместимой с реальным поведением.
about_Scopes: рассказывает о том, как относится к контейнерам, а не к областям (выделение добавлено):
Свойство Visibility переменной или псевдонима определяет, виден ли элемент за пределами контейнера, в котором он был создан. [...] Контейнер может быть модулем, сценарием или оснасткой. Элементы с частной видимостью можно просматривать и изменять только в том контейнере, в котором они были созданы. Если контейнер добавлен или импортирован, элементы с частной видимостью не могут быть просмотрены или изменены.
Оснастки были предшественниками модуля только в двоичном виде из версии 1 и больше не актуальны.
Скрипты не имеют состояния за исключением случаев, когда они выполняются, поэтому идея доступа к его переменным извне обычно неприменима (см. ниже re dot-sources) .
Модули имеют состояние, но все переменные в модуле по умолчанию скрыты от внешнего мира, и нет необходимости задавать специальные свойства переменных. И наоборот, вы должны явно запросить экспорт переменной через Export-ModuleMember -Variable
(а также через запись VariablesToExport
в соответствующем манифесте модуля, если он присутствует).
- Note: For functions, the logic is different, because - unlike variables - all functions are exported by default. To make functions effectively private, i.e. to hide them from consumers of your module, you must switch to explicit exporting: If your module has no manifest, use an
Export-ModuleMember -Function ...
call at the bottom of your script module to select the functions to export explicitly. If you do have a manifest (a satellite *.psd1
file), it is sufficient to list the functions of interest in the FunctionsToExport
entry. Note that both Export-ModuleMember
and the FunctionsToExport
module-manifest entry accept name patterns (wildcards); thus, for instance, if you adopt a convention of using the verb-noun naming convention only for public functions in your module, a FunctionsToExport = @( '*-*' )
entry would automatically limit exporting to the functions implicitly designated as public.
Следовательно, все потребности в видимости должны быть удовлетворены даже без свойства видимости (установленного в Private
):
Как уже говорилось, модули по умолчанию скрывают свои переменные, но допускают явный экспорт; аналогичным образом, функции, видимые извне, можно контролировать с помощью явного экспорта (любые функции, которые вы не экспортируете, неявно скрыты, хотя и без явного экспорта всех). em> видны).
Когда скрипт или функция запускается, они могут скрывать свои переменные от потомков областей действия с помощью Private
option /scope; например.:
$private:foo = 'bar' # create variable only visible in the very same scope
"in same scope: [$foo]" # -> 'in same scope: [bar]'
& { "in child scope: [$foo]" } # -> 'in child scope: []'
Если сценарий предназначен для точечного поиска, то есть для загрузки непосредственно в текущую область с помощью .
operator и вы хотите выборочно скрыть созданные в нем переменные, самое простое решение - заключить такие переменные в & { ... }
, чтобы создать их в дочерней области, которая отбрасывается при выходе из блока скрипта; в качестве альтернативы, но менее надежно, вы также можете очистить явно через Remove-Variable
Что касается применения свойства видимости, начиная с PowerShell 7.1:
Точечный источник сценария из глобальной области кажется единственным сценарием, в котором невидимые переменные не могут быть доступны напрямую в области действия вызывающего объекта.
Запуск такой команды, как
New-Variable -Name 'mytest' -Value 'Foo' -Scope 'Global' -Visibility Private
, непосредственно в интерактивной подсказке равносилен ее размещению в сценарии и выборке этого сценария.
Попытка получить доступ к такой переменной в глобальной области видимости напрямую приводит к ошибке завершения оператора: PermissionDenied: Cannot access the variable '$mytest' because it is a private variable.
Как вы заметили, это ограничение легко обойти, обратившись к переменной через блок скрипта, как . { $mytest }
, так и & { $mytest }
— это работает и со скрытыми командами.
Точечный источник сценария в неглобальной области, например, внутри другого сценария, похоже, вообще не обеспечивает соблюдение ограничения.
Я не знаю, каков был первоначальный замысел дизайна, но:
Я подозреваю, что мы имеем дело с ошибкой, которая не всегда обеспечивает невидимость.
Когда он применяется, любопытно, что невидимая переменная не просто обрабатывается как если бы она не существовала, а ошибка; напротив, невидимая команда действительно выглядит так, как будто ее не существует.[1]
Документация по этой функции в отношении команд, свойство .Visible
[System.Management.Automation.CommandInfo]
предполагает, что эта функция предназначена для доступа вне пространства выполнения (выделение добавлено).
Указывает, разрешено ли выполнение команды по запросу, внешнему по отношению к пространству выполнения.
Подразумевается, что видимость не предназначена для использования внутри сеанса, учитывая, что обычный сеанс PowerShell ограничен одной средой выполнения, за исключением случаев, когда вы явно создаете дополнительные области выполнения через SDK PowerShell.
[1] Как вы уже поняли, можно управлять видимостью команд, в том числе и функций, а именно с помощью файла [System.Management.Automation.CommandInfo]
, например, возвращенное Get-Command
командлет; например: (Get-Command myFunc).Visibility = 'Private'
person
mklement0
schedule
10.12.2020