Як отримати поточний файл, що виконується PowerShell?


92

Примітка: PowerShell 1.0
Я хотів би отримати поточне ім'я файлу PowerShell. Тобто, якщо я розпочну сеанс так:

powershell.exe .\myfile.ps1

Я хотів би отримати рядок ". \ Myfile.ps1" (або щось подібне). EDIT : "myfile.ps1" є кращим.
Будь-які ідеї?


Дякую, поточні відповіді майже однакові, але мені потрібно лише ім'я файлу (а не весь шлях), тому прийнятою відповіддю є @ Keith's. Однак +1 до обох відповідей. Тепер я знаю про річ $ MyInvocation :-)
Рон Кляйн,

Як щодо отримання батьківського сценарію з включеного сценарію?
Флорін Сабау,

Відповіді:


67

Я намагався узагальнити різні відповіді тут, оновлені для PowerShell 5:

  • Якщо ви використовуєте лише PowerShell 3 або новішої версії, використовуйте $PSCommandPath

  • Якщо ви хочете сумісність зі старими версіями, вставте прокладку:

    if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath; }

    Це додає, $PSCommandPathякщо воно ще не існує.

    Код шима може виконуватися де завгодно (верхній рівень або всередині функції), хоча $PSCommandPathзмінна підпорядковується нормальним правилам масштабування (наприклад, якщо ви вкладете шим у функцію, змінна встановлюється лише для цієї функції).

Деталі

У різних відповідях використовуються 4 різні методи, тому я написав цей сценарій, щоб продемонструвати кожен (плюс $PSCommandPath):

function PSCommandPath() { return $PSCommandPath; }
function ScriptName() { return $MyInvocation.ScriptName; }
function MyCommandName() { return $MyInvocation.MyCommand.Name; }
function MyCommandDefinition() {
    # Begin of MyCommandDefinition()
    # Note: ouput of this script shows the contents of this function, not the execution result
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()
}
function MyInvocationPSCommandPath() { return $MyInvocation.PSCommandPath; }

Write-Host "";
Write-Host "PSVersion: $($PSVersionTable.PSVersion)";
Write-Host "";
Write-Host "`$PSCommandPath:";
Write-Host " *   Direct: $PSCommandPath";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.ScriptName:";
Write-Host " *   Direct: $($MyInvocation.ScriptName)";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Name:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Name)";
Write-Host " * Function: $(MyCommandName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Definition:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Definition)";
Write-Host " * Function: $(MyCommandDefinition)";
Write-Host "";
Write-Host "`$MyInvocation.PSCommandPath:";
Write-Host " *   Direct: $($MyInvocation.PSCommandPath)";
Write-Host " * Function: $(MyInvocationPSCommandPath)";
Write-Host "";

Вихід:

PS C:\> .\Test\test.ps1

PSVersion: 5.1.19035.1

$PSCommandPath:
 *   Direct: C:\Test\test.ps1
 * Function: C:\Test\test.ps1

$MyInvocation.ScriptName:
 *   Direct:
 * Function: C:\Test\test.ps1

$MyInvocation.MyCommand.Name:
 *   Direct: test.ps1
 * Function: MyCommandName

$MyInvocation.MyCommand.Definition:
 *   Direct: C:\Test\test.ps1
 * Function:
    # Begin of MyCommandDefinition()
    # Note this is the contents of the MyCommandDefinition() function, not the execution results
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()


$MyInvocation.PSCommandPath:
 *   Direct:
 * Function: C:\Test\test.ps1

Примітки:

  • Виконується з C:\, але фактичний сценарій є C:\Test\test.ps1.
  • Жоден метод не повідомляє про пройдений шлях виклику ( .\Test\test.ps1)
  • $PSCommandPath це єдиний надійний спосіб, але він був представлений у PowerShell 3
  • У версіях до 3 жоден метод не працює як усередині, так і зовні функції

7
Для кожного, хто читає сьогодні (2017), він повинен читати ЦЮ публікацію як правильну відповідь! +1
Коллін Чаффін

2
@CollinChaffin: погоджено, і зараз (2017) зараз найменш підтримуваною є Windows 7, тому немає причин не використовувати, $PSCommandPathякщо застаріла версія (WindowsXP) не потрібна.
тукан

Перший приклад коду є хибним, оскільки він містить два визначення однієї і тієї ж функції ( function PSCommandPath) та посилання на неправильну функцію ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)";- чи я пропускаю щось очевидне?
Майк Л'Анджело,

@ MikeL'Angelo Ти маєш рацію! Пройшов непоміченим протягом 3 років. Виправлено, дякую. Результат і висновок однакові.
gregmac

81

Хоча поточна відповідь правильна в більшості випадків, існують певні ситуації, коли вона не дасть вам правильної відповіді. Якщо ви використовуєте всередині своїх функцій сценарію, тоді:

$MyInvocation.MyCommand.Name 

Повертає ім'я функції замість імені імені сценарію.

function test {
    $MyInvocation.MyCommand.Name
}

Дасть вам " тест " незалежно від назви вашого сценарію. Правильна команда для отримання імені сценарію - це завжди

$MyInvocation.ScriptName

це повертає повний шлях сценарію, який ви виконуєте. Якщо вам потрібна лише назва файлу сценарію, тоді цей код повинен вам допомогти:

split-path $MyInvocation.PSCommandPath -Leaf

6
Зверніть увагу, що на верхньому рівні ім'я сценарію не визначене з шикарним v4. Мені подобається використовувати на верхньому рівні $ MyInvocation.MyCommand.Definition для повного шляху чи імені відповідно до інших відповідей.
AnneTheAgile

30
$MyInvocation.ScriptNameповернути для мене порожній рядок, PS v3.0.
JohnC

4
@JohnC $MyInvocation.ScriptNameпрацює лише зсередини функції. Дивіться мою відповідь нижче .
gregmac

72

Якщо вам потрібна лише назва файлу (а не повний шлях), використовуйте це:

$ScriptName = $MyInvocation.MyCommand.Name

32

Спробуйте наступне

$path =  $MyInvocation.MyCommand.Definition 

Це може не дати вам фактично введений шлях, але це дасть вам дійсний шлях до файлу.


1
@Hamish у питанні конкретно сказано, якщо воно викликане з файлу.
JaredPar

FYI: Це дасть вам повний шлях та ім'я файлу (Powershell 2.0)
Ральф Віллгосс,

Я шукав саме цю команду. Дякую, ДжаредПар! :)
sqlfool

Використовувати Split-Path для отримання каталогу? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse

7

Якщо ви шукаєте поточний каталог, в якому виконується сценарій, ви можете спробувати цей:

$fullPathIncFileName = $MyInvocation.MyCommand.Definition
$currentScriptName = $MyInvocation.MyCommand.Name
$currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "")

Write-Host $currentExecutingPath

1
Це не спрацювало б правильно C:\ilike.ps123\ke.ps1, правда?
fridojet

@fridojet - Не впевнений, не біля терміналу PS, щоб перевірити його. Чому ти не пробуєш і не бачиш?
Ryk

Ні, просто риторичне запитання ;-) - Це було б цілком логічно, оскільки Replace()метод замінює кожен випадок голки (а не лише останній випадок), і я також тестував його. Однак приємна ідея зробити щось на зразок віднімання на рядки.
fridojet

... А як щодо String.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName))? - Він працює коректно: "Ich bin Hamster".TrimEnd("ster")повертає Ich bin Hamі "Ich bin Hamsterchen".TrimEnd("ster")повертає Ich bin Hamsterchen(замістьIch bin Hamchen ) - Чудово!
fridojet

$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
YP

7

будьте обережні: На відміну від змінних $PSScriptRootі $PSCommandPathавтоматичних змінних, властивості PSScriptRootі PSCommandPathвластивості $MyInvocationавтоматичної змінної містять інформацію про скрипт, що викликає або викликає, а не про поточний сценарій.

напр

PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ...
=!C:\Users\S_ms\OneDrive\Documents\DPM.ps1

... де DPM.ps1містить

Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath)

4

Я б стверджував, що існує кращий метод, встановивши область дії змінної $ MyInvocation.MyCommand.Path:

ех> $ script : MyInvocation.MyCommand.Name

Цей метод працює за будь-яких обставин виклику:

ПРИКЛАД: Somescript.ps1

function printme () {
    "In function:"
    ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
    ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
    ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
}
"Main:"
( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
" "
printme
exit

ВИХІД:

PS> powershell C:\temp\test.ps1
Main:
MyInvocation.ScriptName:
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: test.ps1

In function:
MyInvocation.ScriptName: C:\temp\test.ps1
script:MyInvocation.MyCommand.Name: test.ps1
MyInvocation.MyCommand.Name: printme

Зверніть увагу, як прийнята вище відповідь НЕ повертає значення при виклику з Main. Також зверніть увагу, що прийнята вище відповідь повертає повний шлях, коли запитання вимагало лише назву сценарію. Змінна сфери дії працює в усіх місцях.

Крім того, якщо ви хочете отримати повний шлях, ви просто зателефонуєте:

$script:MyInvocation.MyCommand.Path

3

Як зазначалось у попередніх відповідях, використання "$ MyInvocation" підлягає проблемам з масштабом і не обов'язково надає узгоджені дані (повернене значення проти значення прямого доступу). Я виявив, що "найчистішим" (найбільш послідовним) методом отримання інформації про сценарій, як шлях до сценарію, ім'я, парми, командний рядок тощо, незалежно від сфери застосування (у основних або наступних / вкладених викликах функцій), є використання "Get- Змінна "на" MyInvocation "...

# Get the MyInvocation variable at script level
# Can be done anywhere within a script
$ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value

# Get the full path to the script
$ScriptPath = $ScriptInvocation.MyCommand.Path

# Get the directory of the script
$ScriptDirectory = Split-Path $ScriptPath

# Get the script name
# Yes, could get via Split-Path, but this is "simpler" since this is the default return value
$ScriptName = $ScriptInvocation.MyCommand.Name

# Get the invocation path (relative to $PWD)
# @GregMac, this addresses your second point
$InvocationPath = ScriptInvocation.InvocationName

Отже, ви можете отримати ту ж інформацію, що і $ PSCommandPath, але набагато більше в угоді. Не впевнений, але схоже на те, що "Get-Variable" був недоступний до PS3, тож не дуже допомагає справді старим (не оновленим) системам.

Існує також кілька цікавих аспектів використання "-Scope", оскільки ви можете повернутися назад, щоб отримати імена тощо функцій, що викликають. 0 = поточний, 1 = батьківський тощо.

Сподіваюся, це дещо корисно.

Посилання, https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable


1

Провів тестування з наступним сценарієм, як на PS 2, так і на PS 4, і мав однакові результати. Сподіваюся, це допомагає людям.

$PSVersionTable.PSVersion
function PSscript {
  $PSscript = Get-Item $MyInvocation.ScriptName
  Return $PSscript
}
""
$PSscript = PSscript
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

""
$PSscript = Get-Item $MyInvocation.InvocationName
$PSscript.FullName
$PSscript.Name
$PSscript.BaseName
$PSscript.Extension
$PSscript.DirectoryName

Результати -

Major  Minor  Build  Revision
-----  -----  -----  --------
4      0      -1     -1      

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts

C:\PSscripts\Untitled1.ps1
Untitled1.ps1
Untitled1
.ps1
C:\PSscripts

1

Це може працювати в більшості версій PowerShell:

(& { $MyInvocation.ScriptName; })

Це може працювати для запланованої роботи

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.