我如何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。 (括号中的术语是以下结果表的关键字。)
- 内嵌代码[inline]
- 内联函数,即主程序中的函数[内联函数]
- 点源function,即相同的function移动到一个单独的.ps1文件[点源]
- 模块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