Làm cách nào để tải tệp thực thi PowerShell hiện tại?


92

Lưu ý: PowerShell 1.0
Tôi muốn lấy tên tệp PowerShell đang thực thi hiện tại. Đó là, nếu tôi bắt đầu phiên của mình như thế này:

powershell.exe .\myfile.ps1

Tôi muốn lấy chuỗi ". \ Myfile.ps1" (hoặc cái gì đó tương tự). CHỈNH SỬA : "myfile.ps1" thích hợp hơn.
Bất kỳ ý tưởng?


Cảm ơn, các câu trả lời hiện tại gần như giống nhau, nhưng tôi chỉ cần tên tệp (chứ không phải toàn bộ đường dẫn), vì vậy câu trả lời được chấp nhận là @ Keith's. +1 cho cả hai câu trả lời, mặc dù. Bây giờ tôi biết về điều $ MyInvocation :-)
Ron Klein

Làm thế nào về việc lấy tập lệnh mẹ từ một tập lệnh bao gồm?
Florin Sabau

Câu trả lời:


67

Tôi đã cố gắng tóm tắt các câu trả lời khác nhau ở đây, được cập nhật cho PowerShell 5:

  • Nếu bạn chỉ sử dụng PowerShell 3 trở lên, hãy sử dụng $PSCommandPath

  • Nếu muốn tương thích với các phiên bản cũ hơn, hãy chèn miếng đệm:

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

    Điều này sẽ thêm $PSCommandPathnếu nó chưa tồn tại.

    Mã shim có thể được thực thi ở bất kỳ đâu (cấp cao nhất hoặc bên trong một hàm), mặc dù $PSCommandPathbiến phải tuân theo các quy tắc xác định phạm vi thông thường (ví dụ: nếu bạn đặt miếng đệm vào một hàm, thì biến chỉ được xác định phạm vi cho hàm đó).

Chi tiết

Có 4 phương pháp khác nhau được sử dụng trong các câu trả lời khác nhau, vì vậy tôi đã viết tập lệnh này để chứng minh mỗi (cộng $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 "";

Đầu ra:

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

Ghi chú:

  • Thực thi từ C:\, nhưng kịch bản thực tế là C:\Test\test.ps1.
  • Không có phương thức nào cho bạn biết đường dẫn lệnh gọi đã truyền ( .\Test\test.ps1)
  • $PSCommandPath là cách đáng tin cậy duy nhất, nhưng đã được giới thiệu trong PowerShell 3
  • Đối với các phiên bản trước 3, không có phương pháp nào hoạt động cả bên trong và bên ngoài một hàm

7
Đối với bất kỳ ai đọc ngày hôm nay (2017), họ nên đọc bài đăng NÀY là câu trả lời chính xác! +1
Collin Chaffin

2
@CollinChaffin: đã đồng ý và bây giờ (2017) ít được hỗ trợ nhất hiện nay là Windows 7, vì vậy không có lý do gì để không sử dụng $PSCommandPathnếu kế thừa (WindowsXP) không được yêu cầu.
tukan

Ví dụ mã đầu tiên bị thiếu sót vì nó chứa hai định nghĩa của cùng một hàm ( function PSCommandPath) và một tham chiếu đến hàm sai ( Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)";- hoặc tôi đang bỏ qua điều gì đó rõ ràng?
Mike L'Angelo

@ MikeL'Angelo Bạn nói đúng! Đã không được chú ý trong 3 năm. Đã sửa, cảm ơn bạn. Đầu ra và kết luận là giống nhau mặc dù.
gregmac

81

Mặc dù câu trả lời hiện tại là đúng trong hầu hết các trường hợp, nhưng có một số trường hợp nó sẽ không cho bạn câu trả lời chính xác. Nếu bạn sử dụng bên trong các hàm script của mình thì:

$MyInvocation.MyCommand.Name 

Trả về tên của hàm thay vì tên của tập lệnh.

function test {
    $MyInvocation.MyCommand.Name
}

Sẽ cung cấp cho bạn " bài kiểm tra " bất kể kịch bản của bạn được đặt tên như thế nào. Lệnh phù hợp để lấy tên tập lệnh luôn là

$MyInvocation.ScriptName

điều này trả về đường dẫn đầy đủ của tập lệnh mà bạn đang thực thi. Nếu bạn chỉ cần tên tệp script thì mã này sẽ giúp bạn:

split-path $MyInvocation.PSCommandPath -Leaf

6
Lưu ý rằng ở cấp cao nhất, Scriptname không được xác định với posh v4. Tôi thích sử dụng ở cấp cao nhất, $ MyInvocation.MyCommand.Definition cho đường dẫn đầy đủ hoặc Tên theo các câu trả lời khác.
AnneTheAgile

30
$MyInvocation.ScriptNametrả lại chuỗi trống cho tôi, PS v3.0.
JohnC

4
@JohnC $MyInvocation.ScriptNamechỉ hoạt động từ bên trong một hàm. Xem câu trả lời của tôi dưới đây .
gregmac

72

Nếu bạn chỉ muốn tên tệp (không phải đường dẫn đầy đủ), hãy sử dụng:

$ScriptName = $MyInvocation.MyCommand.Name

32

Hãy thử những điều sau đây

$path =  $MyInvocation.MyCommand.Definition 

Điều này có thể không cung cấp cho bạn đường dẫn thực tế được nhập vào nhưng nó sẽ cung cấp cho bạn một đường dẫn hợp lệ đến tệp.


1
@Hamish câu hỏi cho biết cụ thể nếu được gọi từ một tệp.
JaredPar

FYI: Đây cung cấp cho bạn đường dẫn đầy đủ và tên tập tin (Powershell 2.0)
Ralph Willgoss

Tôi đã tìm kiếm chính xác lệnh này. Cảm ơn bạn, JaredPar! :)
sqlfool

Sử dụng Split-Path để lấy thư mục? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
Underverse

7

Nếu bạn đang tìm kiếm thư mục hiện tại mà tập lệnh đang được thực thi, bạn có thể thử thư mục này:

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

Write-Host $currentExecutingPath

1
Điều đó sẽ không hoạt động chính xác C:\ilike.ps123\ke.ps1, phải không?
fridojet

@fridojet - Không chắc chắn, không ở gần thiết bị đầu cuối PS để kiểm tra nó. Tại sao bạn không thử nó và xem?
Ryk

Không, chỉ là một câu hỏi tu từ ;-) - Nó sẽ rất hợp lý vì Replace()phương pháp này sẽ thay thế mọi lần xuất hiện của kim (không chỉ lần xuất hiện cuối cùng) và tôi cũng đã thử nghiệm nó. Tuy nhiên, bạn nên làm điều gì đó như phép trừ trên chuỗi.
fridojet

... Còn String.TrimEnd()( $currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName)) thì sao? - Nó hoạt động chính xác: "Ich bin Hamster".TrimEnd("ster")trả về Ich bin Ham"Ich bin Hamsterchen".TrimEnd("ster")trả lại Ich bin Hamsterchen(thay vì Ich bin Hamchen) - Tốt!
fridojet

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

7

Hãy cẩn thận: Không giống như $PSScriptRoot$PSCommandPathcác biến tự động, các thuộc tính PSScriptRootPSCommandPaththuộc tính của $MyInvocationbiến tự động chứa thông tin về tập lệnh gọi hoặc lệnh gọi, không phải tập lệnh hiện tại.

ví dụ

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

... nơi DPM.ps1chứa

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

4

Tôi tranh luận rằng có một phương pháp tốt hơn, bằng cách đặt phạm vi của biến $ MyInvocation.MyCommand.Path:

ex> $ script : MyInvocation.MyCommand.Name

Phương pháp này hoạt động trong tất cả các trường hợp gọi:

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

ĐẦU RA:

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

Lưu ý rằng câu trả lời được chấp nhận ở trên KHÔNG trả về giá trị khi được gọi từ Main. Ngoài ra, lưu ý rằng câu trả lời được chấp nhận ở trên trả về đường dẫn đầy đủ khi câu hỏi chỉ yêu cầu tên tập lệnh. Biến phạm vi hoạt động ở mọi nơi.

Ngoài ra, nếu bạn muốn đường dẫn đầy đủ, thì bạn chỉ cần gọi:

$script:MyInvocation.MyCommand.Path

3

Như đã lưu ý trong các câu trả lời trước, việc sử dụng "$ MyInvocation" có thể gặp phải các vấn đề về phạm vi và không nhất thiết phải cung cấp dữ liệu nhất quán (giá trị trả về so với giá trị truy cập trực tiếp). Tôi nhận thấy rằng phương pháp "sạch nhất" (nhất quán nhất) để lấy thông tin tập lệnh như đường dẫn tập lệnh, tên, mệnh lệnh, dòng lệnh, v.v. bất kể phạm vi (trong lệnh gọi hàm chính hoặc tiếp theo / lồng nhau) là sử dụng "Get- Biến "trên" 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

Vì vậy, bạn có thể nhận được thông tin tương tự như $ PSCommandPath, nhưng nhiều hơn nữa trong giao dịch. Không chắc chắn, nhưng có vẻ như "Get-Variable" không có sẵn cho đến PS3 nên không có nhiều trợ giúp cho các hệ thống thực sự cũ (chưa được cập nhật).

Ngoài ra còn có một số khía cạnh thú vị khi sử dụng "-Scope" vì bạn có thể quay ngược lại để lấy tên, v.v. của (các) hàm gọi. 0 = hiện tại, 1 = cha mẹ, v.v.

Hy vọng điều này là hữu ích phần nào.

Tham khảo, https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable


1

Đã thực hiện một số thử nghiệm với tập lệnh sau, trên cả PS 2 và PS 4 và có cùng kết quả. Tôi hy vọng điều này sẽ giúp mọi người.

$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

Các kết quả -

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

Điều này có thể hoạt động trên hầu hết các phiên bản powershell:

(& { $MyInvocation.ScriptName; })

Điều này có thể hoạt động cho Công việc đã lên lịch

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.