Каков наилучший способ определения местоположения текущего PowerShell script?
Всякий раз, когда мне нужно сослаться на общий модуль или скрипт, мне нравится использовать пути относительно текущего файла скрипта. Таким образом, мой скрипт всегда может найти другие скрипты в библиотеке.
Итак, что является лучшим, стандартным способом определения каталога текущего скрипта? В настоящее время я делаю:
$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
Я знаю, что в модулях (.psm1) вы можете использовать $PSScriptRoot
для получения этой информации, но она не устанавливается в обычных скриптах (т.е. файлах .ps1).
Какой канонический способ получить текущее местоположение файла скрипта PowerShell?
Ответы
Ответ 1
PowerShell 3+
# This is an automatic variable set to the current file's/module directory
$PSScriptRoot
PowerShell 2
До PowerShell 3 не было лучшего способа, чем запрашивать
Свойство MyInvocation.MyCommand.Definition
для общих скриптов. У меня была следующая строка вверху практически каждого скрипта PowerShell, который у меня был:
$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
Ответ 2
Если вы создаете модуль V2, вы можете использовать автоматическую переменную, называемую
$PSScriptRoot
.
Из PS > Справка automatic_variable
$PSScriptRoot
Contains the directory from which the script module is being executed.
This variable allows scripts to use the module path to access other
resources.
Ответ 3
Для PowerShell 3.0
$PSCommandPath
Contains the full path and file name of the script that is being run.
This variable is valid in all scripts.
Функция:
function Get-ScriptDirectory {
Split-Path -Parent $PSCommandPath
}
Ответ 4
Для PowerShell 3+
function Get-ScriptDirectory {
if ($psise) {
Split-Path $psise.CurrentFile.FullPath
}
else {
$global:PSScriptRoot
}
}
Я разместил эту функцию в своем профиле. Это работает в ISE, используя F8/Run Selection тоже.
Ответ 5
Может быть, я чего-то здесь упускаю... но если вам нужен настоящий рабочий каталог, вы можете просто использовать это: (Get-Location).Path
для строки или Get-Location
для объекта.
Если вы не имеете в виду нечто подобное, что я понимаю после прочтения вопроса снова.
function Get-Script-Directory
{
$scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
return Split-Path $scriptInvocation.MyCommand.Path
}
Ответ 6
Очень похоже на уже опубликованные ответы, но pipeопроводы кажутся более похожими на PowerShell:
$PSCommandPath | Split-Path -Parent
Ответ 7
Я использую автоматическую переменную $ ExecutionContext. Это работает от PowerShell 2 и позже. $ ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath( '\')
$ ExecutionContext Содержит объект EngineIntrinsics, который представляет контекст выполнения хоста Windows PowerShell. Ты можешь используйте эту переменную, чтобы найти объекты выполнения, которые доступно для командлетов.
Ответ 8
Мне нужно знать имя script и где оно выполняется.
Префикс "$ global:" в структуру MyInvocation возвращает полный путь и имя script при вызове из основного script и основной строки импортированного файла библиотеки .PSM1. Он также работает из функции в импортированной библиотеке.
После долгих разворачиваний я решил использовать $global: MyInvocation.InvocationName.
Он надежно работает с запуском CMD, Run With Powershell и ISE.
Как локальные, так и UNC запускают правильный путь.
Ответ 9
Мне потребовалось некоторое время, чтобы разработать что-то, что приняло принятый ответ и превратило его в надежную функцию.
Я не уверен насчет других, но я работаю в среде с компьютерами как на PowerShell версии 2, так и на 3, поэтому мне нужно было справиться с обоими. Следующая функция предлагает изящный запасной вариант:
Function Get-PSScriptRoot
{
$ScriptRoot = ""
Try
{
$ScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop
}
Catch
{
$ScriptRoot = Split-Path $script:MyInvocation.MyCommand.Path
}
Write-Output $ScriptRoot
}
Это также означает, что функция ссылается на область действия "Сценарий", а не на родительскую область, как описано Майклом Соренсом в одном из своих постов в блоге.
Ответ 10
Я всегда использую этот небольшой фрагмент, который работает для PowerShell и ISE одинаково:
# Set active path to script-location:
$path = $MyInvocation.MyCommand.Path
if (!$path) {
$path = $psISE.CurrentFile.Fullpath
}
if ($path) {
$path = Split-Path $path -Parent
}
Set-Location $path
Ответ 11
Вы также можете рассмотреть split-path -parent $psISE.CurrentFile.Fullpath
, если какой-либо из других методов завершится с ошибкой. В частности, если вы запустите файл, чтобы загрузить кучу функций, а затем выполните эти функции с помощью оболочки ISE (или если вы запустили), кажется, что функция Get-Script-Directory
, как указано выше, не работает.
Ответ 12
Я обнаружил, что старые решения, опубликованные здесь, не работают для меня на PowerShell V5. Я придумал это:
try {
$scriptPath = $PSScriptRoot
if (!$scriptPath)
{
if ($psISE)
{
$scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
}
else {
Write-Host -ForegroundColor Red "Cannot resolve script file path"
exit 1
}
}
}
catch {
Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
exit 2
}
Write-Host "Path: $scriptPath"
Ответ 13
function func1()
{
$inv = (Get-Variable MyInvocation -Scope 1).Value
#$inv.MyCommand | Format-List *
$Path1 = Split-Path $inv.scriptname
Write-Host $Path1
}
function Main()
{
func1
}
Main