如何找到正在执行的脚本的源路径?

发布于 2024-07-19 03:06:11 字数 146 浏览 11 评论 0原文

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

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

I want to be able to tell what path my executing script was run from.
This will often not be $pwd.

I need to call other scripts that are in a folder structure relative to my script and while I could hard code the paths, that's both distasteful and a bit of a pain in the neck when trying to promote from "dev" to "test" to "production".

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

滥情稳全场 2024-07-26 03:06:11

该无处不在的脚本最初由 Jeffrey Snover 发布PowerShell 团队(在 Skyler 的回答中给出)以及 Keith Cedirc 和 EBGreen 发布的变体都存在严重的缺陷--代码是否报告您期望的内容取决于您调用它的位置!

下面的代码通过简单地引用 script 作用域而不是 parent 解决了这个问题> 范围:

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

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

  1. 内联代码 [inline]
  2. 内联函数,即主程序中的函数 [内联函数]
  3. 点源函数,即同一函数移动到单独的 .ps1 文件中 [dot source]
  4. 模块函数,即移至单独的 .psm1 文件的相同函数 [module]

最后两列显示使用脚本作用域(即 $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 模块和封装

The ubiquitous script originally posted by Jeffrey Snover of the PowerShell team (given in Skyler's answer) and the variations posted by Keith Cedirc, and EBGreen, all suffer from a serious drawback--whether the code reports what you expect depends on where you call it!

My code below overcomes this problem by simply referencing script scope instead of parent scope:

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

To illustrate the problem, I created a test vehicle that evalutes the target expression in four different ways. (The bracketed terms are the keys to the following result table.)

  1. inline code [inline]
  2. inline function, i.e. function in the main program [inline function]
  3. Dot-sourced function, i.e. the same function moved to a separate .ps1 file [dot source]
  4. Module function, i.e. the same function moved to a separate .psm1 file [module]

The last two columns show the result of using script scope (i.e. $script:) or with parent scope (with -scope 1). A result of "script" means that the invocation correctly reported the location of the script. The "module" result means the invocation reported the location of the module containing the function rather than the script that called the function; this indicates a drawback of both functions that you cannot put the function in a module.

Setting the module issue aside the remarkable observation from the table is that using the parent scope approach fails most of the time (in fact, twice as often as it succeeds).

table of input combinations

Finally, here is the test vehicle:

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

Contents of ScriptDirFinder.ps1:

function Get-ScriptDirectory2
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

Contents of ScriptDirFinder.psm1:

function Get-ScriptDirectory3
{
    Split-Path $script:MyInvocation.MyCommand.Path
#   $Invocation = (Get-Variable MyInvocation -Scope 1).Value
#   Split-Path $Invocation.MyCommand.Path
}

I am not familiar with what was introduced in PowerShell 2, but it could very well be that script scope did not exist in PowerShell 1, at the time Jeffrey Snover published his example.

I was surprised when, though I found his code example proliferated far and wide on the web, it failed immediately when I tried it! But that was because I used it differently than Snover's example (I called it not at script-top but from inside another function (my "nested twice" example).)

2011.09.12 Update

You can read about this with other tips and tricks on modules in my just-published article on Simple-Talk.com:
Further Down the Rabbit Hole: PowerShell Modules and Encapsulation.

黄昏下泛黄的笔记 2024-07-26 03:06:11

您将问题标记为 Powershell 1.0 版,但是,如果您有权访问 Powershell 3.0 版,您知道有 $PSCommandPath$PSScriptRoot,这使得获取脚本路径变得更容易。 请参阅本页的“其他脚本功能”部分了解更多信息。

You tagged your question for Powershell version 1.0, however, if you have access to Powershell version 3.0 you know have $PSCommandPathand$PSScriptRootwhich makes getting the script path a little easier. Please refer to the "OTHER SCRIPT FEATURES" section on this page for more information.

情丝乱 2024-07-26 03:06:11

多年来,我们在大多数脚本中都使用这样的代码,没有出现任何问题:

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1

We've been using code like this in most of our scripts for several years with no problems:

#--------------------------------------------------------------------
# Dot source support scripts
#--------------------------------------------------------------------
$ScriptPath = $MyInvocation.MyCommand.Path
$ScriptDir  = Split-Path -Parent $ScriptPath
. $ScriptDir\BuildVars.ps1
. $ScriptDir\LibraryBuildUtils.ps1
. $ScriptDir\BuildReportUtils.ps1
沉鱼一梦 2024-07-26 03:06:11

我最近遇到了同样的问题。 以下文章帮助我解决了问题: 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

I ran into the same issue recently. The following article helped me solve the problem: http://blogs.msdn.com/powershell/archive/2007/06/19/get-scriptdirectory.aspx

If you're not interested in how it works, here's all the code you need per the article:

function Get-ScriptDirectory
{
$Invocation = (Get-Variable MyInvocation -Scope 1).Value
Split-Path $Invocation.MyCommand.Path
}

And then you get the path by simply doing:

$path = Get-ScriptDirectory
妄断弥空 2024-07-26 03:06:11

我认为您可以使用找到正在运行的脚本的路径

$MyInvocation.MyCommand.Path

希望它有帮助!

塞德里克

I think you can find the path of your running script using

$MyInvocation.MyCommand.Path

Hope it helps !

Cédric

烏雲後面有陽光 2024-07-26 03:06:11

这是 PS 中的奇怪之处之一(至少在我看来)。 我确信这是有充分理由的,但对我来说仍然很奇怪。 因此:

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

This is one of those oddities (to my mind at least) in PS. I'm sure there is a perfectly good reason for it, but it still seems odd to me. So:

If you are in a script but not in a function then $myInvocation.InvocationName will give you the full path including the script name. If you are in a script and inside a function then $myInvocation.ScriptName will give you the same thing.

天涯沦落人 2024-07-26 03:06:11

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

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  

Thank you msorens! This really helped me with my custom module. In case anyone is interested in making their own, here is how mine is structured.

MyModule (folder)
 - MyModule.psd1 (help New-ModuleManifest)
 - MyScriptFile.ps1 (ps1 files are easy to test)

You then reference MyScriptFile.ps1 in MyModule.psd1. Referencing the .ps1 in the NestedModules array will place the functions in the module session state rather than the global session state. (How to Write a Module Manifest)

NestedModules = @('.\MyScriptFile.ps1','.\MyOtherScriptFile.ps1')

Content of MyScriptFile.ps1

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

try {
    Export-ModuleMember -Function "*-*"
}
catch{}

The try/catch hides the error from Export-ModuleMember when running MyScriptFile.ps1

Copy the MyModule directory to one of the paths found here $env:PSModulePath

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

CommandType     Name                                               ModuleName                                                                                                                                                
-----------     ----                                               ----------                                                                                                                                                
Function        Get-ScriptDirectory                                MyModule  
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文