【问题标题】:Find the location (path) of the main PowerShell script file查找主 PowerShell 脚本文件的位置(路径)
【发布时间】:2020-02-05 13:41:14
【问题描述】:

我正在寻找一种方法来获取主(比如说“入口点”)PowerShell 脚本 (*.ps1) 文件的路径。

让我们以下面的例子为例:

  • 我有以下文件:

“C:\MyDir1\Main.ps1”调用中的函数

"C:\MyDir2\SubDir1\MyModule.psm1" 中调用函数

“C:\AnotherDir\AnotherScript.ps1”

  • 我运行以下 PowerShell 命令:

"PowerShell.exe -File "C:\MyDir1\Main.ps1"

  • 我想要什么:从脚本“AnotherScript.ps1”中,我想找到“C:\MyDir1\Main.ps1”的路径。

注意 1: 请注意,我不是在谈论可通过 $PSScriptRoot 变量获得的当前脚本的路径。

注意 2: 看来变量 $global:PSScriptRoot(与 $PSScriptRoot 不同) 是我正在寻找的,但不幸的是,当从 PowerShell 会话调用主脚本时,此值为空。

【问题讨论】:

  • 你可以试试@(Get-PSCallStack)[1].ScriptName@(Get-PSCallStack)[1].Location
  • 我已经通过 Get-PSCallStack,这是一种可能,但是我们必须根据入口点的启动方式(从 PowerShell 会话或从 powershell)获取最后一个元素或最后一个元素.exe -文件“Script.ps1”)。
  • 在这种情况下,@(Get-PSCallStack)[-1].ScriptName 不可以吗?
  • @(Get-PSCallStack)[-1].ScriptName 并不总是有效,因为 'ScriptName' 在从 PowerShell 提示符调用脚本时为空(如 [PS C:\ Temp>.MainScript.ps1])

标签: powershell


【解决方案1】:

这是一个可以完成这项工作的函数,但它非常棘手(可能太多了)。

function Get-EntryPointAbsFilePath() {

    # NOTE 1: Do not use '$MyInvocation.PSScriptRoot' because it corresponds to the path of the calling script (not entry point script).
    # NOTE 2: '$global:PSScriptRoot' is not the same as '$PSScriptRoot' and seems to correspond to the entry point script directory,
    # but it is set only when the main script is invoked from powershell command like [PowerShell.exe -File "MainScript.ps1"] but not
    # when "MainScript.ps1" is invoked from a PowerShell session (prompt) like [PS C:\Temp>. MainScript.ps1].
    $CallStack = Get-PSCallStack

    # We take the last stack element (correponding to the first call).
    # The 'ScriptName' property of this first call can be null when the main script is invoked from a PowerShell session like [PS C:\Temp>. MainScript.ps1].
    # This is because PowerShell first evaluates the entered command.
    $FirstCall = $CallStack[$CallStack.Count - 1];
    if ($null -ne $FirstCall.ScriptName) {
        return $FirstCall.ScriptName;
    }

    # We take the second call (assuming that we are run under a PowerShell session).
    # To make sure this call is coming from the execution of a script file (and not from the execution a cmdlet in the interpreter, like a function in a module),
    # we check the 'FunctionName' property which equals "<ScriptBlock>" when a call is performed from a script block, like a ps1 file.
    # This test is not required for the first call, as a PowerShell module can't be run.
    $SecondCall = $CallStack[$CallStack.Count - 2];
    if ($null -ne $SecondCall.ScriptName -and $SecondCall.FunctionName -eq "<ScriptBlock>") {
        return $SecondCall.ScriptName;
    }

    throw "No PowerShell entry point script could be found. This cmdlet ""$($MyInvocation.MyCommand.Name)"" is intended to be called only via the execution of a script file.";
}

【讨论】:

  • 那为什么不做一个像Get-PSCallStack | ForEach-Object { &lt;check .ScriptName and break loop if not $null&gt;}这样的ForEch-Object
  • 为了控制所有可能的用例。如果超过 2 个级别,我想抛出,因为这种情况不应该发生。
猜你喜欢
  • 2020-10-13
  • 2017-03-21
  • 1970-01-01
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多