我如何find执行脚本的源代码path?

我想能够告诉我的执行脚本从哪个path运行。
这通常不会是$密码。

我需要调用与脚本相关的文件夹结构中的其他脚本,并且可以对path进行硬编码,但是当试图从“dev”升级到“test”时,这样做会让人感到不愉快和痛苦“生产”。

PowerShell团队的Jeffrey Snover (在Skyler的回答中给出的 )以及Keith Cedirc和EBGreen发布的变体都有一个严重的缺点 – 代码是否报告了您期望的内容取决于您在哪里调用它!

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

function Get-ScriptDirectory { Split-Path $script:MyInvocation.MyCommand.Path } 

为了说明这个问题,我创build了一个testing工具,以四种不同的方式评估目标expression。 (括号中的术语是以下结果表的关键字。)

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

最后两列显示使用脚本作用域(即$ script :)或父作用域(使用-scope 1)的结果。 “脚本”的结果意味着调用正确报告脚本的位置。 “模块”结果意味着调用报告了包含函数的模块的位置,而不是调用该函数的脚本; 这表明两个函数的缺点是你不能把函数放在模块中。

将模块问题放在一边,从表中可以看出, 使用父范围方法在大多数情况下都失败了 (事实上​​,成功的两倍)。

输入组合表

最后,这里是testing车辆:

 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 

ScriptDirFinder.ps1的内容:

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

ScriptDirFinder.psm1的内容:

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

我对PowerShell 2中引入的内容并不熟悉,但在Jeffrey Snover发表他的示例时,PowerShell 1中并不存在脚本范围。

当我发现他的代码示例在网上泛滥,我感到惊讶,当我尝试时,它立即失败! 但那是因为我使用它不同于Snover的例子(我不是在脚本顶部,而是从另一个函数内部(我的“嵌套两次”示例)。

2011.09.12更新

你可以在Simple-Talk.com上刚刚发表的文章中阅读关于这个模块的其他提示和技巧: 更深入的研究兔子洞:PowerShell模块和封装 。

但是,如果您有权访问Powershell版本3.0,则可以使用$PSCommandPath$PSScriptRoot ,从而使脚本path变得更简单。 请参阅本页上的“其他脚本function”一节以获取更多信息。

在我们的大多数脚本中,我们一直使用这样的代码几年没有问题:

 #-------------------------------------------------------------------- # Dot source support scripts #-------------------------------------------------------------------- $ScriptPath = $MyInvocation.MyCommand.Path $ScriptDir = Split-Path -Parent $ScriptPath . $ScriptDir\BuildVars.ps1 . $ScriptDir\LibraryBuildUtils.ps1 . $ScriptDir\BuildReportUtils.ps1 

我想你可以find你正在运行的脚本使用的path

 $MyInvocation.MyCommand.Path 

希望能帮助到你 !

塞德里克

我最近遇到了同样的问题。 下面的文章帮我解决了这个问题: 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 } 

然后你就可以简单地做到这一点:

 $path = Get-ScriptDirectory 

这是PS中那些古怪的东西之一(至less在我看来)。 我确信这有一个很好的理由,但对我来说似乎还是很奇怪。 所以:

如果你在一个脚本,但不是在一个函数中,那么$ myInvocation.InvocationName将为您提供包括脚本名称的完整path。 如果你在一个脚本和一个函数内,那么$ myInvocation.ScriptName会给你同样的东西。

谢谢msorens! 这真的帮助我与我的自定义模块。 如果有人有兴趣制作自己的,这里是我的结构。

 MyModule (folder) - MyModule.psd1 (help New-ModuleManifest) - MyScriptFile.ps1 (ps1 files are easy to test) 

然后在MyModule.psd1中引用MyScriptFile.ps1。 引用NestedModules数组中的.ps1会将函数置于模块会话状态而不是全局会话状态。 ( 如何写模块清单 )

 NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1') 

MyScriptFile.ps1的内容

 function Get-ScriptDirectory { Split-Path $script:MyInvocation.MyCommand.Path } try { Export-ModuleMember -Function "*-*" } catch{} 

运行MyScriptFile.ps1时,try / catch隐藏了Export-ModuleMember中的错误

MyModule目录复制到这里find的$ env:PSModulePathpath之一

 PS C:\>Import-Module MyModule PS C:\>Get-Command -Module MyModule CommandType Name ModuleName ----------- ---- ---------- Function Get-ScriptDirectory MyModule