我希望能够告诉我执行脚本的运行路径。
这往往不是$ pwd。
我需要调用相对于我的脚本的文件夹结构中的其他脚本,虽然我可以对路径进行硬编码,但是当尝试从“dev”推广到“dev”时,这既令人反感又有点痛苦测试“到”生产“。
答案 0 :(得分:95)
最初由PowerShell团队的Jeffrey Snover发布的无处不在的脚本(在Skyler's answer中给出)以及Keith Cedirc和EBGreen发布的变体都存在严重缺陷 - 是否代码报告您的期望取决于您调用它的位置!
我的代码通过简单地引用脚本范围而不是父范围来克服此问题:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
为了说明问题,我创建了一种测试工具,以四种不同的方式评估目标表达。 (括号内的术语是以下结果表的关键。)
最后两列显示使用脚本范围(即$ 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
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中引入的内容,但很可能在Jeffhell Snover发布他的示例时,PowerShell 1中不存在脚本范围。
当我发现他的代码示例在网络上广泛扩散时,我很惊讶,当我尝试它时它立即失败了!但那是因为我使用它的方式与Snover的例子不同(我不是在脚本顶部而是从另一个函数内部调用它(我的“嵌套两次”示例)。)
2011.09.12更新
您可以在我刚刚发布的Simple-Talk.com上的文章中阅读有关模块的其他提示和技巧: Further Down the Rabbit Hole: PowerShell Modules and Encapsulation
答案 1 :(得分:19)
您为Powershell 1.0版标记了您的问题,但是,如果您有权访问Powershell 3.0版,那么您知道$PSCommandPath
和$PSScriptRoot
可以让脚本路径更容易一些。请参阅"OTHER SCRIPT FEATURES" section on this page for more information.
答案 2 :(得分:11)
我们在大多数脚本中使用这样的代码已经好几年没有问题了:
#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1
答案 3 :(得分: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
}
然后你通过简单地做到了:
$path = Get-ScriptDirectory
答案 4 :(得分:5)
我认为您可以使用
找到正在运行的脚本的路径$MyInvocation.MyCommand.Path
希望它有所帮助!
和Cédric
答案 5 :(得分:1)
这是PS中的一些奇怪的事情(至少在我看来)。我确信它有一个很好的理由,但对我来说仍然很奇怪。所以:
如果您在脚本中但不在函数中,那么$ myInvocation.InvocationName将为您提供包括脚本名称的完整路径。如果您在脚本中并且在函数内部,那么$ myInvocation.ScriptName将为您提供相同的功能。
答案 6 :(得分:0)
MyModule (folder)
- MyModule.psd1 (help New-ModuleManifest)
- MyScriptFile.ps1 (ps1 files are easy to test)
然后在MyModule.psd1中引用MyScriptFile.ps1。引用NestedModules数组中的.ps1将使函数处于模块会话状态而不是全局会话状态。 (How to Write a Module Manifest)
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 目录复制到此处找到的路径之一 $ env:PSModulePath
PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule
CommandType Name ModuleName
----------- ---- ----------
Function Get-ScriptDirectory MyModule