Программирование

Как найти каталог текущего скрипта PowerShell на Windows

Узнайте надёжный способ получить путь к текущему скрипту PowerShell. Используем $PSScriptRoot, $PSCommandPath и MyInvocation для совместимости с PS2+.

What’s the best way to figure out where the current PowerShell script is located?

You know, whenever I need to reference a common module or script, I prefer using paths relative to the current script file. That way, my script can always find other scripts in the library without any issues.

So, what’s the most reliable, standard method for determining the directory of the current script? Right now, I’m using this approach:

powershell
$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

I’m aware that in modules (.psm1 files), you can use $PSScriptRoot to get this info, but unfortunately that variable doesn’t get set in regular scripts (like .ps1 files).

What’s the canonical or recommended way to get the current PowerShell script file’s location?

Самый простой и надёжный способ найти каталог выполняемого скрипта – дать PowerShell сам вернуть путь.

  • PowerShell 3 + автоматически предоставляет $PSScriptRoot, который содержит полный путь к каталогу, где находится исполняемый скрипт (или модуль).
  • Для более старых версий (PowerShell 2) или если хочется быть более точным, используйте $MyInvocation.MyCommand.Path (или свойство Definition) и разбейте его на каталог с помощью Split‑Path.

Ниже вы найдёте быстрый справочник и несколько практических советов.


Содержание


Как работают автоматические переменные $PSScriptRoot и $PSCommandPath 

Переменная Что хранит Когда доступна
$PSScriptRoot Полный путь к каталогу, содержащему исполняемый скрипт или модуль PowerShell 3.0+ (внутри скрипта, модуля, или функции, объявленной в файле)
$PSCommandPath Полный путь к файлу скрипта, который сейчас исполняется PowerShell 5.1+ (внутри скрипта)

Why $PSScriptRoot?
It mirrors the behaviour of $PSScriptRoot in modules and is the most concise, reliable way to reference files that live alongside your script.
See the official documentation on the PowerShell FAQ for details: PowerShell FAQ – Script root.


Проверка совместимости и откат к $MyInvocation 

Если ваш скрипт должен работать в PowerShell 2, используйте MyInvocation:

powershell
# В PowerShell 2 и выше
$ScriptPath = $MyInvocation.MyCommand.Path   # или .Definition
$ScriptDir  = Split-Path -Parent $ScriptPath

Совет – проверяйте наличие $PSScriptRoot перед использованием:

powershell
if ($null -ne $PSScriptRoot) {
    $ScriptDir = $PSScriptRoot
} else {
    $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
}

Это гарантирует совместимость и позволяет использовать $PSScriptRoot там, где он доступен, а MyInvocation в качестве резервного решения.
См. обсуждение на Stack Overflow: What’s the best way to determine the location of the current PowerShell script?.


Пример полного скрипта с относительными путями 

powershell
# 1️⃣ Определяем каталог текущего скрипта
$ScriptDir = if ($null -ne $PSScriptRoot) { $PSScriptRoot } else { Split-Path -Parent $MyInvocation.MyCommand.Path }

# 2️⃣ Путь к модулю, который лежит рядом
$ModulePath = Join-Path -Path $ScriptDir -ChildPath 'MyCommonModule.psm1'

# 3️⃣ Загружаем модуль
Import-Module -Name $ModulePath -Force

# 4️⃣ Теперь можно использовать функции из модуля
Invoke-MyCommonFunction

Что здесь важно?

  • Join-Path гарантирует корректную конкатенацию путей на всех ОС.
  • Import-Module с -Force полезен, если скрипт переисполняется.

Часто задаваемые вопросы 

Вопрос Ответ
Может ли $PSScriptRoot использоваться в интерактивной сессии? Нет – переменная определяется только при выполнении кода из файла. В интерактивной сессии она будет $null.
Как получить полное имя файла скрипта, а не только каталог? Используйте $PSCommandPath (PowerShell 5.1+) или $MyInvocation.MyCommand.Path.
Что делать, если скрипт запускается через & {} или Invoke-Expression? В таких случаях $PSScriptRoot остаётся $null; используйте $MyInvocation.MyCommand.Path в сочетании с Resolve-Path.
Можно ли использовать $MyInvocation в модулях? Да, но $PSScriptRoot предпочтительнее, потому что он всегда указывает на каталог модуля, даже если вызывается из другого скрипта.

Заключение 

  • Для PowerShell 3+: просто "$PSScriptRoot" – самый надёжный способ.
  • Для совместимости с PowerShell 2: Split-Path -Parent $MyInvocation.MyCommand.Path.
  • Если нужен полный путь к файлу: $PSCommandPath (если доступен) или $MyInvocation.MyCommand.Path.
  • Всегда проверяйте $null – в интерактивных сессиях переменные не инициализируются.

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


Источники 

  1. What’s the best way to determine the location of the current PowerShell script? – Stack Overflow
  2. PowerShell FAQ – Script root
  3. Get the Current Directory Path or Script Location in PowerShell – SharePoint Diary
  4. How to Get Current Directory Full Path in PowerShell? – ShellGeek
Авторы
Проверено модерацией
Модерация
Как найти каталог текущего скрипта PowerShell на Windows