如何找到执行脚本的源路径?

Kev*_*han 61 powershell powershell-1.0

我希望能够告诉我执行脚本的运行路径.
这往往不是$ pwd.

我需要调用相对于我的脚本的文件夹结构中的其他脚本,虽然我可以对路径进行硬编码,但是当尝试从"开发"升级到"测试"时,这既令人反感又有点痛苦"生产".

Mic*_*ens 99

最初由PowerShell团队的Jeffrey Snover发布的无处不在的脚本(Skyler的答案中给出)以及Keith Cedirc和EBGreen发布的变体都有严重的缺点 - 代码是否报告您所期望的取决于您所称的位置!

我的代码通过简单地引用脚本范围而不是范围来克服这个问题:

function Get-ScriptDirectory
{
    Split-Path $script:MyInvocation.MyCommand.Path
}
Run Code Online (Sandbox Code Playgroud)

为了说明这个问题,我创建了一个测试工具,以四种不同的方式评估目标表达.(括号内的术语是以下结果表的关键.)

  1. 内联代码[inline]
  2. 内联函数,即主程序中的函数[内联函数]
  3. 点源函数,即将相同的函数移动到单独的.ps1文件[点源]
  4. 模块功能,即将相同的功能移到单独的.psm1文件[模块]

最后两列显示了使用脚本范围(即$ script :)或父范围(使用-scope 1)的结果."脚本"的结果意味着调用正确地报告了脚本的位置."模块"结果表示调用报告了包含函数的模块的位置,而不是调用函数的脚本; 这表明这两个函数的缺点是您无法将该函数放入模块中.

除了表中的显着观察之外,设置模块问题是使用父范围方法在大多数情况下失败(事实上​​,成功的频率是其成功的两倍).

输入组合表

最后,这是测试车辆:

function DoubleNested()
{
    "=== DOUBLE NESTED ==="
    NestCall
}

function NestCall()
{
    "=== NESTED ==="
    "top level:"
    Split-Path $script:MyInvocation.MyCommand.Path
    #$foo = (Get-Variable MyInvocation -Scope 1).Value
    #Split-Path $foo.MyCommand.Path
    "immediate func call"
    Get-ScriptDirectory1
    "dot-source call"
    Get-ScriptDirectory2
    "module call"
    Get-ScriptDirectory3
}

function Get-ScriptDirectory1
{
    Split-Path $script:MyInvocation.MyCommand.Path
    # $Invocation = (Get-Variable MyInvocation -Scope 1).Value
    # Split-Path $Invocation.MyCommand.Path
}

. .\ScriptDirFinder.ps1
Import-Module ScriptDirFinder -force

"top level:"
Split-Path $script:MyInvocation.MyCommand.Path
#$foo = (Get-Variable MyInvocation -Scope 1).Value
#Split-Path $foo.MyCommand.Path

"immediate func call"
Get-ScriptDirectory1
"dot-source call"
Get-ScriptDirectory2
"module call"
Get-ScriptDirectory3

NestCall
DoubleNested
Run Code Online (Sandbox Code Playgroud)

ScriptDirFinder.ps1的内容:

function Get-ScriptDirectory2
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}
Run Code Online (Sandbox Code Playgroud)

ScriptDirFinder.psm1的内容:

function Get-ScriptDirectory3
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}
Run Code Online (Sandbox Code Playgroud)

我不熟悉PowerShell 2中引入的内容,但很可能在Jeffhell Snover发布他的示例时,PowerShell 1中不存在脚本范围.

当我发现他的代码示例在网络上广泛扩散时,我感到很惊讶,当我尝试它时它立即失败了!但那是因为我使用它的方式不同于Snover的例子(我不是在脚本顶部而是从另一个函数内部调用它(我的"嵌套两次"示例).)

2011.09.12更新

您可以在我刚刚发布的关于Simple-Talk.com的文章中的模块上阅读有关此内容的其他提示和技巧: 进一步了解Rabbit Hole:PowerShell模块和封装.


Mic*_*ley 21

你标记你的问题PowerShell的1.0版本,但是,如果你有机会到PowerShell的3.0版本,你知道有$PSCommandPath$PSScriptRoot这使得越来越脚本路径变得更容易一些.有关更多信息,请参阅本页"其他脚本功能"部分.


Kei*_*ill 11

我们在大多数脚本中使用这样的代码已经好几年没有问题了:

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1
Run Code Online (Sandbox Code Playgroud)

  • 请注意,从函数内部调用时不会出现这种情况. (2认同)

Sky*_*ler 6

我最近遇到了同样的问题.以下文章帮助我解决了这个问题:http://blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

如果您对它的工作原理不感兴趣,请参阅本文所需的所有代码:

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}
Run Code Online (Sandbox Code Playgroud)

然后,您只需执行以下操作即可获得路径:

$path = Get-ScriptDirectory
Run Code Online (Sandbox Code Playgroud)


Céd*_*Rup 5

我认为你可以找到运行脚本的路径

$MyInvocation.MyCommand.Path
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你 !

塞德里克

  • 只要您不在函数中,这将为您提供包括脚本名称的完整路径.如果你在一个函数中,那么它将是$ null. (4认同)