如何获取当前 PowerShell 执行文件?

注意: PowerShell 1.0
我想得到当前正在执行的 PowerShell 文件名,也就是说,如果我像这样开始我的会话:

powershell.exe .\myfile.ps1

我想得到字符串 “ . myfile. ps1”(或类似的东西)。
有什么想法吗?

167844 次浏览

Try the following

$path =  $MyInvocation.MyCommand.Definition

这可能不会给您输入的实际路径,但它会给您一个有效的文件路径。

如果只想要文件名(而不是完整路径) ,请使用:

$ScriptName = $MyInvocation.MyCommand.Name

如果你正在寻找执行脚本的工作目录,你可以试试这个:

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


Write-Host $currentExecutingPath

虽然当前的答案在大多数情况下是正确的,但是在某些情况下它不会给您正确的答案。如果你在你的脚本函数中使用:

$MyInvocation.MyCommand.Name

返回函数的名称,而不是脚本的名称。

function test {
$MyInvocation.MyCommand.Name
}

将给你“ 测试”无论你的脚本是如何命名。 获取脚本名称的正确命令始终是

$MyInvocation.ScriptName

这将返回正在执行的脚本的完整路径。如果您只需要脚本文件名,这段代码应该可以帮助您:

split-path $MyInvocation.PSCommandPath -Leaf

当心: 与 $PSScriptRoot$PSCommandPath自动变量不同, PSScriptRootPSCommandPath属性的 $MyInvocation自动 变量包含有关调用程序或调用脚本的信息,而不包含 现在的剧本。

e.g.

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

...where DPM.ps1 contains

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

Did some testing with the following script, on both PS 2 and PS 4 and had the same result. I hope this helps people.

$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

I've tried to summarize the various answers here, updated for PowerShell 5:

  • 如果只使用 PowerShell 3或更高版本,请使用 $PSCommandPath

  • 如果想与旧版本兼容,插入垫片:

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

    如果 $PSCommandPath还不存在,这将添加 $PSCommandPath

    The shim code can be executed anywhere (top-level or inside a function), though $PSCommandPath variable is subject to normal scoping rules (eg, if you put the shim in a function, the variable is scoped to that function only).

细节

有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: $(PSCommandPath)";
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
  • 没有方法告诉您 passed调用路径(.\Test\test.ps1)
  • $PSCommandPath is the only reliable way, but was introduced in PowerShell 3
  • For versions prior to 3, no single method works both inside and outside of a function

I would argue that there is a better method, by setting the scope of the variable $MyInvocation.MyCommand.Path:

ex> $剧本:MyInvocation.MyCommand.Name

这种方法适用于调用的所有情况:

一些脚本

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

Notice how the above accepted answer does NOT return a value when called from Main. Also, note that the above accepted answer returns the full path when the question requested the script name only. The scoped variable works in all places.

另外,如果你想要完整的路径,那么你只需要调用:

$script:MyInvocation.MyCommand.Path

As noted in previous responses, using "$MyInvocation" is subject to scoping issues and doesn't necessarily provide consistent data (return value vs. direct access value). I've found that the "cleanest" (most consistent) method for getting script info like script path, name, parms, command line, etc. regardless of scope (in main or subsequent/nested function calls) is to use "Get-Variable" on "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 相同的信息,但是在这个交易中要多得多。不确定,但是看起来“获取变量”在 PS3之前是不可用的,所以对于真正老的(没有更新的)系统没有太多帮助。

在使用“-Scope”时,还有一些有趣的方面,因为您可以回溯以获得调用函数的名称等。0 = 当前,1 = 父,等等。

希望这对你有所帮助。

裁判 https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable

这可以在大多数 Powershell 版本上运行:

(& { $MyInvocation.ScriptName; })

这可以适用于计划作业

Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command

简短演示一下@gregmac 的答案(非常好,而且非常详细) ,它基本上推荐使用 $PSCommandPath作为唯一可靠的命令来返回使用 Powershell 3.0及以上版本的当前运行的脚本。

这里显示返回完整路径或只返回文件名。

测试1:

'Direct:'
$PSCommandPath  # Full Path
Split-Path -Path $PSCommandPath -Leaf  # File Name only


function main () {
''
'Within a function:'
$PSCommandPath
Split-Path -Path $PSCommandPath -Leaf
}


main

产出:

PS> .\Test.ps1
Direct:
C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1
Test.ps1


Within a function:
C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1
Test.ps1