查找主PowerShell脚本文件的位置(路径)

查找主PowerShell脚本文件的位置(路径),powershell,Powershell,我正在寻找获取主(比如“入口点”)PowerShell脚本(*.ps1)文件路径的方法 让我们考虑下面的例子: 我有以下文件: “C:\MyDir1\Main.ps1”调用 “C:\MyDir2\SubDir1\MyModule.psm1”,它调用 “C:\AnotherDir\AnotherScript.ps1” 我运行以下PowerShell命令: PowerShell.exe-文件“C:\MyDir1\Main.ps1” 我想要的:从脚本“AnotherScript.ps1”中,

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

让我们考虑下面的例子:

  • 我有以下文件:
“C:\MyDir1\Main.ps1”调用

“C:\MyDir2\SubDir1\MyModule.psm1”,它调用

“C:\AnotherDir\AnotherScript.ps1”

  • 我运行以下PowerShell命令:
PowerShell.exe-文件“C:\MyDir1\Main.ps1”

  • 我想要的:从脚本“AnotherScript.ps1”中,我想要找到“C:\MyDir1\Main.ps1”的路径
注意1:请注意,我不是说当前脚本的路径,它可以通过$PSScriptRoot变量获得


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

这里有一个函数可以完成此任务,但它非常复杂(可能太复杂)

函数Get-EntryPointAbsFilePath(){ #注意1:不要使用“$MyInvocation.PSScriptRoot”,因为它对应于调用脚本的路径(而不是入口点脚本)。 #注2:“$global:PSScriptRoot”与“$PSScriptRoot”不同,似乎对应于入口点脚本目录, #但仅当从powershell命令(如[powershell.exe-File“MainScript.ps1”)调用主脚本时,才设置该值,而不是 #从PowerShell会话(提示符)调用“MainScript.ps1”时,如[PS C:\Temp>.MainScript.ps1]。 $CallStack=获取PSCallStack #我们使用最后一个堆栈元素(对应于第一个调用)。 #当从PowerShell会话(如[PS C:\Temp>.MainScript.ps1])调用主脚本时,此第一次调用的“ScriptName”属性可以为null。 #这是因为PowerShell首先计算输入的命令。 $FirstCall=$CallStack[$CallStack.Count-1]; if($null-ne$FirstCall.ScriptName){ 返回$FirstCall.ScriptName; } #我们接受第二个调用(假设我们在PowerShell会话下运行)。 #要确保此调用来自脚本文件的执行(而不是来自解释器中cmdlet的执行,如模块中的函数), #当从脚本块(如ps1文件)执行调用时,我们检查等于“”的“FunctionName”属性。 #第一次调用不需要此测试,因为无法运行PowerShell模块。 $SecondCall=$CallStack[$CallStack.Count-2]; if($null-ne$SecondCall.ScriptName-和$SecondCall.FunctionName-eq“”){ 返回$SecondCall.ScriptName; } throw“找不到PowerShell入口点脚本。此cmdlet“$($MyInvocation.MyCommand.Name)”仅可通过执行脚本文件来调用。“; }
您可以尝试
@(Get-PSCallStack)[1]。ScriptName
@(Get-PSCallStack)[1]。位置
我已经完成Get-PSCallStack,这是一种可能性,但我们必须根据入口点的启动方式(从PowerShell会话或从PowerShell.exe文件“Script.ps1”)获取最后一个元素或最后一个元素。在这种情况下,
@(Get-PSCallStack)[-1]。ScriptName
会做这个把戏吗?@(Get-PSCallStack)[-1]。ScriptName并不总是做这个把戏,因为当从PowerShell提示符(如[PS C:\Temp>.MainScript.ps1])调用脚本时,“ScriptName”是空的(如[PS C:\Temp>.MainScript.ps1]),那么为什么不做一个类似
Get PSCallStack | ForEach对象{的ForEch对象呢
以控制所有可能的用例。我想在超过两个级别时抛出,因为这种情况不应该发生。
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.";
}