Как я могу выбрать между $MyInvocate.ScriptName и $MyInvocate.PSCommandPath в PowerShell?

В PowerShell 5.1+ существуют следующие переменные, обе из которых, похоже, предлагают полный путь к «вызывающему» сценарию (т. е. сценарию, который вызвал этот сценарий, например, из модуля, функции или внешнего сценария):

$MyInvocation.ScriptName
$MyInvocation.PSCommandPath

Я могу найти официальную документацию, в которой упоминаются оба варианта:

...[$MyInvoction.]ScriptName относится к имени скрипта, который вам позвонил (Да – наверное, стоило выбрать имя получше)

[$MyInvoction.]PSCommandPath содержит полный путь и имя скрипта, который вызвал или вызвал текущий скрипт.

Какой из них мне следует использовать? Мои текущие теории и наблюдения:

Есть ли еще какие-нибудь странные случаи или скрытые «подводные камни» с любым из них, о которых мне следует знать? Или я должен знать о ситуациях, когда одно должно быть предпочтительнее другого?

Если у вас версия 5.1+: просто используйте $PSCommandPath. ScriptName действительно является пережитком PowerShell 2.0.

Mathias R. Jessen 21.05.2024 12:47

Согласен с Матиасом, не могу придумать место, где ScriptName может пригодиться. Также не знаю, как можно ответить на этот вопрос, у вас уже есть факты об обоих свойствах, вам решать, какой из них вы хотите использовать.

Santiago Squarzon 21.05.2024 18:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

вр; доктор

  • Для симметрии с одноименной автоматической переменной $PSCommandPath (которая отражает полный путь к файлу работающего скрипта) лучше использовать $MyInvocation.PSCommandPath (которая отражает путь к вызывающему скрипту, если таковой имеется).

    • Тем не менее, старый эквивалент $MyInvocation.ScriptName продолжит работать, но я советую избегать его из-за его неясного названия; Однако есть и положительная сторона: в нем нет обнаруженной вами причуды $null (см. далее).
  • К сожалению, у $MyInvocation.PSCommandPath последнего есть особенность/ошибка: при отсутствии вызывающего сценария он сообщает $null, а не '' (пустую строку) — см. выпуск GitHub #23828.

    • Вы можете избежать этой проблемы в будущем, проверив этот случай таким образом, чтобы он одинаково работал с $null и ''; например.:
      • $noParentScript = -not $MyInvocation.PSCommandPath - то есть вы можете положиться на логическое приведение PowerShell, которое приводит как $null, так и '' к $false
      • $noParentScript = $MyInvocation.PSCommandPath -like '' - в контексте подстановочного знака , совпадающего с -like, $null принуждается к ''

Исходная информация

Автоматические переменные $PSCommandPath и $PSScriptRoot были введены в PowerShell v3 (выпущенной в 2012 году) для отражения полного пути к файлу и полного пути к каталогу выполняемого сценария соответственно.

Помимо того, что они проще, чем то, что вам нужно было сделать в версиях 1 и 2 — $MyInvocation.MyCommand.Path и Split-Path -Parent $MyInvocation.MyCommand.Path — эти переменные работают последовательно, а именно также в (скриптовых) модулях.

Для симметрии с недавно введенными автоматическими переменными в v3 $MyInvocation были присвоены новые свойства с тем же именем, т.е. $MyInvocation.PSCommandPath и $MyInvocation.PSScriptRoot, которые сообщают аналогичную информацию о вызывающем объекте работающего сценария, т. е. вызывающем сценарии.

Таким образом, эти свойства могут не иметь значений в скрипте, вызываемом непосредственно из интерактивного сеанса или через Invoke-Expression.

Точно так же, как $PSCommandPath сейчас (в основном) дублирует старый $MyInvocation.MyCommand.Path, так же и $MyInvocation.PSCommandPath (в основном) по отношению к старшему - и, к сожалению, названному - $MyInvocation.ScriptName

В версии 3+ (версия 2, к счастью, сейчас встречается редко), поэтому лучше использовать следующее:

  • чтобы подумать о работающем скрипте: $PSCommandPath и $PSScriptRoot
  • чтобы отразить сценарий вызова, если таковой имеется: $MyInvocation.PSCommandPath и $MyInvocation.PSScriptRoot

Как вы заметили, есть странность: $MyInvocation.PSCommandPath сообщает $null, а не '' (пустую строку). если скрипт вызова отсутствует, в отличие от $MyInvocation.PSScriptRoot (и в отличие от старого эквивалента $MyInvocation.PSCommandPath, $MyInvocation.ScriptName).

Это следует рассматривать как ошибку — простую оплошность в реализации, приводящую к неловкой асимметрии. Я сообщил об этом в выпуске GitHub #23828, хотя и не уверен, что это будет исправлено, тем более что может существовать код, который явно проверяет $null.

Отличный ответ, спасибо. Лично я считаю, что возврат $null более интуитивен, чем «пустая строка». Вы хотите сказать, что пустая строка больше соответствует другим подобным переменным?

Minkus 22.05.2024 13:16

Рад слышать, что это помогло, @Minkus; Не за что. По поводу $null: если бы это был C#, я бы согласился, но PowerShell не позволяет хранить $null в переменных и параметрах типа [string]; например, '' -eq [string] $null — это $true, и аналогично [string] $str = $null хранит '', а не $null. И да, есть еще более непосредственная несогласованность: $MyInvocation.PSScriptRoot возвращает '', а не $null, если нет сценария вызова.

mklement0 22.05.2024 17:04

Другие вопросы по теме