我希望能够知道我的执行脚本是从哪个路径运行的。
这通常不是 $pwd。
我需要调用与我的脚本相关的文件夹结构中的其他脚本,虽然我可以对路径进行硬编码,但在尝试从“开发”升级到“测试”时,这既令人反感,又有点让人头疼“生产”。
我希望能够知道我的执行脚本是从哪个路径运行的。
这通常不是 $pwd。
我需要调用与我的脚本相关的文件夹结构中的其他脚本,虽然我可以对路径进行硬编码,但在尝试从“开发”升级到“测试”时,这既令人反感,又有点让人头疼“生产”。
最初由PowerShell 团队的Jeffrey Snover发布的无处不在的脚本(在Skyler 的回答中给出)以及 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 中引入的内容,但很可能是 PowerShell 1 中不存在脚本范围,当时 Jeffrey Snover 发布了他的示例。
当我发现他的代码示例在网络上广泛传播时,我感到很惊讶,但当我尝试时它立即失败了!但那是因为我使用它与 Snover 的示例不同(我不是在脚本顶部而是从另一个函数内部调用它(我的“嵌套两次”示例)。)
2011.09.12 更新
您可以在我刚刚在 Simple-Talk.com 上发表的文章中阅读有关模块的其他提示和技巧: 进一步深入兔子洞:PowerShell 模块和封装。
您为 Powershell 1.0 版标记了您的问题,但是,如果您可以访问您知道的 Powershell 3.0 版$PSCommandPath
,$PSScriptRoot
这使得获取脚本路径更容易一些。有关详细信息,请参阅此页面上的“其他脚本功能”部分。
几年来,我们在大多数脚本中一直使用这样的代码,没有任何问题:
#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1
我最近遇到了同样的问题。以下文章帮助我解决了这个问题: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
我认为您可以使用找到运行脚本的路径
$MyInvocation.MyCommand.Path
希望能帮助到你 !
塞德里克
这是 PS 中的怪事之一(至少在我看来)。我敢肯定这是有充分理由的,但对我来说仍然很奇怪。所以:
如果您在脚本中但不在函数中,则 $myInvocation.InvocationName 将为您提供包括脚本名称在内的完整路径。如果你在一个脚本和一个函数中,那么 $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目录复制到此处找到的路径之一$env:PSModulePath
PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule
CommandType Name ModuleName
----------- ---- ----------
Function Get-ScriptDirectory MyModule