Bagaimana saya bisa mendapatkan file eksekusi PowerShell saat ini?

94

Catatan: PowerShell 1.0
Saya ingin mendapatkan nama file PowerShell yang sedang dijalankan. Artinya, jika saya memulai sesi saya seperti ini:

powershell.exe .\myfile.ps1

Saya ingin mendapatkan string ". \ Myfile.ps1" (atau sesuatu seperti itu). EDIT : "myfile.ps1" lebih disukai.
Ada ide?

Ron Klein
sumber
Terima kasih, jawaban saat ini hampir sama, tetapi saya hanya perlu nama file (dan bukan seluruh jalur), jadi jawaban yang diterima adalah @ Keith. +1 untuk kedua jawaban. Sekarang saya tahu tentang $ MyInvocation thingy :-)
Ron Klein
Bagaimana dengan mendapatkan skrip induk dari skrip yang disertakan?
Florin Sabau

Jawaban:

73

Saya telah mencoba meringkas berbagai jawaban di sini, diperbarui untuk PowerShell 5:

  • Jika Anda hanya menggunakan PowerShell 3 atau lebih tinggi, gunakan $PSCommandPath

  • Jika ingin kompatibilitas dengan versi yang lebih lama, masukkan shim:

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

    Ini menambahkan $PSCommandPathjika belum ada.

    Kode shim dapat dieksekusi di mana saja (tingkat atas atau di dalam fungsi), meskipun $PSCommandPathvariabel tunduk pada aturan pelingkupan normal (misalnya, jika Anda meletakkan shim dalam suatu fungsi, variabel tersebut dibatasi hanya untuk fungsi itu).

Detail

Ada 4 metode berbeda yang digunakan dalam berbagai jawaban, jadi saya menulis skrip ini untuk menunjukkan masing-masing (plus $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 "";

Keluaran:

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

Catatan:

  • Dieksekusi dari C:\, tetapi skrip sebenarnya adalah C:\Test\test.ps1.
  • Tidak ada metode yang memberi tahu Anda jalur pemanggilan yang diteruskan ( .\Test\test.ps1)
  • $PSCommandPath adalah satu-satunya cara yang dapat diandalkan, tetapi diperkenalkan di PowerShell 3
  • Untuk versi sebelum 3, tidak ada metode tunggal yang berfungsi baik di dalam maupun di luar fungsi
gregmac
sumber
7
Bagi siapa pun yang membaca hari ini (2017), mereka harus membaca posting INI sebagai jawaban yang benar! +1
Collin Chaffin
2
@CollinChaffin: setuju dan sekarang (2017) yang paling tidak didukung saat ini adalah Windows 7 sehingga tidak ada alasan untuk tidak menggunakan $PSCommandPathjika warisan (WindowsXP) tidak diperlukan.
tukan
Contoh kode pertama cacat karena mengandung dua definisi dari fungsi yang sama ( function PSCommandPath) dan referensi ke fungsi yang salah ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)";- atau apakah saya mengabaikan sesuatu yang jelas?
Mike L'Angelo
@ MikeL'Angelo Anda benar! Pergi tanpa disadari selama 3 tahun. Diperbaiki, terima kasih. Output dan kesimpulannya sama.
gregmac
81

Meskipun Jawaban saat ini benar dalam banyak kasus, ada situasi tertentu yang tidak akan memberikan jawaban yang benar. Jika Anda menggunakan di dalam fungsi skrip Anda maka:

$MyInvocation.MyCommand.Name 

Mengembalikan nama fungsi, bukan nama nama skrip.

function test {
    $MyInvocation.MyCommand.Name
}

Akan memberi Anda " tes " tidak peduli bagaimana skrip Anda dinamai. Perintah yang tepat untuk mendapatkan nama skrip selalu

$MyInvocation.ScriptName

ini mengembalikan jalur lengkap dari skrip yang Anda jalankan. Jika Anda hanya membutuhkan nama file skrip daripada kode ini akan membantu Anda:

split-path $MyInvocation.PSCommandPath -Leaf
Lukas Kucera
sumber
6
Perhatikan bahwa di tingkat atas, Nama skrip tidak ditentukan dengan posh v4. Saya suka menggunakan di tingkat atas, $ MyInvocation.MyCommand.Definition untuk jalur lengkap atau Nama sesuai jawaban lainnya.
AnneTheAgile
30
$MyInvocation.ScriptNamekembalikan string kosong untuk saya, PS v3.0.
JohnC
4
@JohnC $MyInvocation.ScriptNamehanya bekerja dari dalam suatu fungsi. Lihat jawaban saya di bawah .
gregmac
72

Jika Anda hanya ingin nama file (bukan path lengkap) gunakan ini:

$ScriptName = $MyInvocation.MyCommand.Name
Keith Hill
sumber
32

Coba berikut ini

$path =  $MyInvocation.MyCommand.Definition 

Ini mungkin tidak memberi Anda jalur sebenarnya yang diketik, tetapi ini akan memberi Anda jalur yang valid ke file.

JaredPar
sumber
1
@Hamish pertanyaan secara khusus mengatakan jika dipanggil dari file.
JaredPar
FYI: Ini memberi Anda jalur lengkap dan nama file (Powershell 2.0)
Ralph Willgoss
Saya sedang mencari perintah ini dengan tepat. Terima kasih, JaredPar! :)
sqlfool
Gunakan Split-Path untuk mendapatkan direktori? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse
7

Jika Anda mencari direktori saat ini tempat skrip dijalankan, Anda dapat mencoba yang ini:

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

Write-Host $currentExecutingPath
Ryk
sumber
1
Itu tidak akan bekerja dengan benar C:\ilike.ps123\ke.ps1, bukan?
fridojet
@fridojet - Tidak yakin, bukan di dekat terminal PS untuk mengujinya. Mengapa Anda tidak mencobanya dan melihat?
Ryk
Tidak, hanya pertanyaan retoris ;-) - Ini akan menjadi logis karena Replace()metode ini menggantikan setiap kemunculan jarum (bukan hanya kejadian terakhir) dan saya juga mengujinya. Namun, sebaiknya lakukan sesuatu seperti pengurangan string.
fridojet
... Bagaimana dengan String.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName))? - Ini bekerja dengan benar: "Ich bin Hamster".TrimEnd("ster")kembali Ich bin Hamdan "Ich bin Hamsterchen".TrimEnd("ster")kembali Ich bin Hamsterchen(bukan Ich bin Hamchen) - Baik!
fridojet
$currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
YP
7

berhati-hatilah: Tidak seperti variabel $PSScriptRootdan $PSCommandPathotomatis, properti PSScriptRootdan PSCommandPathdari $MyInvocationvariabel otomatis berisi informasi tentang pemanggil atau skrip pemanggil, bukan skrip saat ini.

misalnya

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

... di mana DPM.ps1berisi

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

Saya berpendapat bahwa ada metode yang lebih baik, dengan menetapkan cakupan variabel $ MyInvocation.MyCommand.Path:

contoh> $ script : MyInvocation.MyCommand.Name

Metode ini berfungsi di semua situasi pemanggilan:

EX: 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

KELUARAN:

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

Perhatikan bagaimana jawaban yang diterima di atas TIDAK mengembalikan nilai saat dipanggil dari Utama. Juga, perhatikan bahwa jawaban yang diterima di atas mengembalikan jalur lengkap ketika pertanyaan meminta nama skrip saja. Variabel cakupan berfungsi di semua tempat.

Juga, jika Anda memang menginginkan jalur lengkap, Anda cukup memanggil:

$script:MyInvocation.MyCommand.Path
Daddio
sumber
3

Seperti disebutkan dalam tanggapan sebelumnya, menggunakan "$ MyInvocation" tunduk pada masalah cakupan dan tidak selalu memberikan data yang konsisten (nilai hasil vs. nilai akses langsung). Saya telah menemukan bahwa metode "terbersih" (paling konsisten) untuk mendapatkan info skrip seperti jalur skrip, nama, parms, baris perintah, dll. Apa pun cakupannya (dalam pemanggilan fungsi utama atau berikutnya / bersarang) adalah dengan menggunakan "Get- Variabel "di" 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

Jadi, Anda bisa mendapatkan info yang sama dengan $ PSCommandPath, tetapi lebih banyak lagi dalam kesepakatan itu. Tidak yakin, tapi sepertinya "Get-Variable" tidak tersedia sampai PS3 jadi tidak banyak bantuan untuk sistem yang benar-benar tua (tidak diperbarui).

Ada juga beberapa aspek menarik saat menggunakan "-Scope" karena Anda dapat mundur untuk mendapatkan nama, dll. Dari fungsi pemanggil. 0 = saat ini, 1 = orang tua, dll.

Semoga ini bisa membantu.

Ref, https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable

AntGut
sumber
1

Melakukan beberapa pengujian dengan script berikut, baik pada PS 2 maupun PS 4 dan mendapatkan hasil yang sama. Saya harap ini membantu orang.

$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

Hasil -

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
Mark Crashley
sumber
1

Ini dapat berfungsi pada sebagian besar versi PowerShell:

(& { $MyInvocation.ScriptName; })

Ini dapat berfungsi untuk Pekerjaan Terjadwal

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
tidak sepertinya
sumber