如何找到正在执行的脚本的源路径?[复制]
-
03-07-2019 - |
题
这个问题在这里已经有答案了:
我希望能够知道我的执行脚本是从哪个路径运行的。
这通常不是 $pwd。
我需要调用与我的脚本相关的文件夹结构中的其他脚本,虽然我可以对路径进行硬编码,但在尝试从“dev”升级到“test”再到“test”时,这既令人厌恶又有点麻烦。 “生产”。
解决方案
最初发布的无处不在的脚本 杰弗里·斯诺弗 PowerShell 团队的成员(在 斯凯勒的回答)以及 Keith Cedirc 和 EBGreen 发布的变体都存在一个严重的缺陷——代码是否报告您期望的内容取决于您调用它的位置!
我的下面的代码通过简单地引用解决了这个问题 脚本 范围而不是 家长 范围:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
为了说明这个问题,我创建了一个测试工具,它以四种不同的方式评估目标表达式。(括号内的术语是下面结果表的关键。)
- 内联代码[内联]
- 内联函数,即主程序中的函数【内联函数】
- 点源函数,即相同的函数移至单独的 .ps1 文件 [点源]
- 模块功能,即相同的功能移至单独的 .psm1 文件 [模块]
最后两列显示使用脚本范围的结果(即$script:) 或使用父范围(使用 -scope 1)。“script”的结果意味着调用正确地报告了脚本的位置。“模块”结果意味着调用报告了包含该函数的模块的位置,而不是调用该函数的脚本;这表明这两个函数都有一个缺点,即您不能将函数放入模块中。
抛开模块问题不谈,表中值得注意的观察结果是: 大多数时候使用父作用域方法会失败 (事实上,成功的频率是其两倍)。
最后,这是测试车辆:
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