这个问题在这里已经有答案了:

我希望能够知道我的执行脚本是从哪个路径运行的。
这通常不是 $pwd。

我需要调用与我的脚本相关的文件夹结构中的其他脚本,虽然我可以对路径进行硬编码,但在尝试从“dev”升级到“test”再到“test”时,这既令人厌恶又有点麻烦。 “生产”。

有帮助吗?

解决方案

最初发布的无处不在的脚本 杰弗里·斯诺弗 PowerShell 团队的成员(在 斯凯勒的回答)以及 Keith Cedirc 和 EBGreen 发布的变体都存在一个严重的缺陷——代码是否报告您期望的内容取决于您调用它的位置!

我的下面的代码通过简单地引用解决了这个问题 脚本 范围而不是 家长 范围:

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

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

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

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

抛开模块问题不谈,表中值得注意的观察结果是: 大多数时候使用父作用域方法会失败 (事实上​​,成功的频率是其两倍)。

table of input combinations

最后,这是测试车辆:

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 版本 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 中的奇怪之处之一(至少在我看来)。我确信这是有充分理由的,但对我来说仍然很奇怪。所以:

如果您位于脚本中但不在函数中,则 $myInspiration.InvocableName 将为您提供包括脚本名称的完整路径。如果您位于脚本和函数内部,那么 $myInvocau.ScriptName 会给您同样的结果。

谢谢姆索伦斯!这对我的自定义模块确实有帮助。如果有人有兴趣自己制作,以下是我的结构。

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 中的错误

复制 我的模块 目录到此处找到的路径之一 $env:PSModulePath

PS C:\>Import-Module MyModule
PS C:\>Get-Command -Module MyModule

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top