【问题标题】:How can I get the current PowerShell executing file?如何获取当前的 PowerShell 执行文件?
【发布时间】:2009-05-03 14:27:09
【问题描述】:

注意:PowerShell 1.0
我想获取当前正在执行的 PowerShell 文件名。也就是说,如果我这样开始我的会话:

powershell.exe .\myfile.ps1

我想得到字符串 ".\myfile.ps1" (或类似的东西)。 编辑"myfile.ps1" 更可取。
有什么想法吗?

【问题讨论】:

  • 谢谢,目前的答案几乎相同,但我只需要文件名(而不是整个路径),所以接受的答案是@Keith's。不过,对这两个答案都 +1。现在我知道了 $MyInvocation 东西 :-)
  • 从包含的脚本中获取父脚本怎么样?

标签: powershell


【解决方案1】:

我试图在这里总结各种答案,针对 PowerShell 5 进行了更新:

  • 如果您只使用 PowerShell 3 或更高版本,请使用 $PSCommandPath

  • 如果想要与旧版本兼容,请插入垫片:

    if ($PSCommandPath -eq $null) { function GetPSCommandPath() { return $MyInvocation.PSCommandPath; } $PSCommandPath = GetPSCommandPath; }

    如果 $PSCommandPath 尚不存在,则会添加它。

    shim 代码可以在任何地方执行(顶层或函数内部),尽管$PSCommandPath 变量受制于正常范围规则(例如,如果您将 shim 放入函数中,则变量的范围仅限于该函数仅)。

详情

各种答案中使用了 4 种不同的方法,所以我编写了这个脚本来演示每种方法(加上 $PSCommandPath):

function PSCommandPath() { return $PSCommandPath; }
function ScriptName() { return $MyInvocation.ScriptName; }
function MyCommandName() { return $MyInvocation.MyCommand.Name; }
function MyCommandDefinition() {
    # Begin of MyCommandDefinition()
    # Note: ouput of this script shows the contents of this function, not the execution result
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()
}
function MyInvocationPSCommandPath() { return $MyInvocation.PSCommandPath; }

Write-Host "";
Write-Host "PSVersion: $($PSVersionTable.PSVersion)";
Write-Host "";
Write-Host "`$PSCommandPath:";
Write-Host " *   Direct: $PSCommandPath";
Write-Host " * Function: $(PSCommandPath)";
Write-Host "";
Write-Host "`$MyInvocation.ScriptName:";
Write-Host " *   Direct: $($MyInvocation.ScriptName)";
Write-Host " * Function: $(ScriptName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Name:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Name)";
Write-Host " * Function: $(MyCommandName)";
Write-Host "";
Write-Host "`$MyInvocation.MyCommand.Definition:";
Write-Host " *   Direct: $($MyInvocation.MyCommand.Definition)";
Write-Host " * Function: $(MyCommandDefinition)";
Write-Host "";
Write-Host "`$MyInvocation.PSCommandPath:";
Write-Host " *   Direct: $($MyInvocation.PSCommandPath)";
Write-Host " * Function: $(MyInvocationPSCommandPath)";
Write-Host "";

输出:

PS C:\> .\Test\test.ps1

PSVersion: 5.1.19035.1

$PSCommandPath:
 *   Direct: C:\Test\test.ps1
 * Function: C:\Test\test.ps1

$MyInvocation.ScriptName:
 *   Direct:
 * Function: C:\Test\test.ps1

$MyInvocation.MyCommand.Name:
 *   Direct: test.ps1
 * Function: MyCommandName

$MyInvocation.MyCommand.Definition:
 *   Direct: C:\Test\test.ps1
 * Function:
    # Begin of MyCommandDefinition()
    # Note this is the contents of the MyCommandDefinition() function, not the execution results
    return $MyInvocation.MyCommand.Definition;
    # End of MyCommandDefinition()


$MyInvocation.PSCommandPath:
 *   Direct:
 * Function: C:\Test\test.ps1

注意事项:

  • C:\执行,但实际脚本是C:\Test\test.ps1
  • 没有方法告诉你通过调用路径(.\Test\test.ps1)
  • $PSCommandPath 是唯一可靠的方法,但在 PowerShell 3 中引入
  • 对于 3 之前的版本,没有一种方法可以同时在函数内部和外部工作

【讨论】:

  • 对于今天(2017 年)阅读的任何人,他们应该将这篇文章作为正确答案阅读! +1
  • @CollinChaffin:同意,现在 (2017) 目前支持最少的是 Windows 7,因此如果不需要旧版 (WindowsXP),没有理由不使用 $PSCommandPath
  • 第一个代码示例有缺陷,因为它包含同一函数的两个定义 (function PSCommandPath) 和对错误函数的引用 (Write-Host " * Direct: $PSCommandPath"; Write-Host " * Function: $(ScriptName)"; - 还是我忽略了一些明显的东西?
  • @MikeL'Angelo 你是对的! 3年无人问津。已修复,谢谢。输出和结论是一样的。
  • 一个长答案,$PSCommandPath 在 99% 的情况下就足够了。不过还是谢谢。
【解决方案2】:

虽然当前答案在大多数情况下是正确的,但在某些情况下它不会给您正确的答案。如果您在脚本函数中使用,则:

$MyInvocation.MyCommand.Name 

返回函数名而不是脚本名。

function test {
    $MyInvocation.MyCommand.Name
}

无论你的脚本如何命名,都会给你“test”。 获取脚本名称的正确命令始终是

$MyInvocation.ScriptName

这将返回您正在执行的脚本的完整路径。如果您只需要脚本文件名,那么此代码应该可以帮助您:

split-path $MyInvocation.PSCommandPath -Leaf

【讨论】:

  • 请注意,在顶层,Scriptname 未使用 posh v4 定义。我喜欢在顶层使用 $MyInvocation.MyCommand.Definition 作为完整路径或根据其他答案的名称。
  • $MyInvocation.ScriptName 为我返回空字符串,PS v3.0。
  • @JohnC $MyInvocation.ScriptName 只能在函数内部工作。见my answer below
【解决方案3】:

如果您只想要文件名(而不是完整路径),请使用:

$ScriptName = $MyInvocation.MyCommand.Name

【讨论】:

  • 对于全局范围之外的任何使用都是错误的。如果您创建一个函数并在函数中调用此代码,您将获得函数的名称而不是文件的名称。
【解决方案4】:

试试下面的

$path =  $MyInvocation.MyCommand.Definition 

这可能不会为您提供输入的实际路径,但会为您提供文件的有效路径。

【讨论】:

  • @Hamish 这个问题特别说明了如果从文件中调用。
  • 仅供参考:这将为您提供完整路径和文件名 (Powershell 2.0)
  • 我正在寻找这个命令。谢谢你,贾里德帕尔! :)
  • 使用拆分路径获取目录? $path = Split-Path $MyInvocation.MyCommand.Definition -Parent
【解决方案5】:

注意: 与 $PSScriptRoot$PSCommandPath 自动变量不同, $MyInvocation 自动的 PSScriptRootPSCommandPath 属性 变量包含有关调用者或调用脚本的信息,而不是 当前脚本。

例如

PS C:\Users\S_ms\OneDrive\Documents> C:\Users\SP_ms\OneDrive\Documents\DPM ...
=!C:\Users\S_ms\OneDrive\Documents\DPM.ps1

...DPM.ps1 包含在哪里

Write-Host ("="+($MyInvocation.PSCommandPath)+"!"+$PSCommandPath)

【讨论】:

    【解决方案6】:

    如果您正在寻找正在执行脚本的当前目录,您可以试试这个:

    $fullPathIncFileName = $MyInvocation.MyCommand.Definition
    $currentScriptName = $MyInvocation.MyCommand.Name
    $currentExecutingPath = $fullPathIncFileName.Replace($currentScriptName, "")
    
    Write-Host $currentExecutingPath
    

    【讨论】:

    • 这在C:\ilike.ps123\ke.ps1 上无法正常工作,对吗?
    • @fridojet - 不确定,不在 PS 终端附近进行测试。为什么不试试看呢?
    • 不,只是一个反问句 ;-) - 这是合乎逻辑的,因为 Replace() 方法替换了 每一次 出现的针头(不仅仅是最后一次出现)和我也测试了它。但是,对字符串执行减法之类的操作是个好主意。
    • ...String.TrimEnd() ($currentExecutingPath = $fullPathIncFileName.TrimEnd($currentScriptName)) 呢? - 它工作正常:"Ich bin Hamster".TrimEnd("ster") 返回 Ich bin Ham"Ich bin Hamsterchen".TrimEnd("ster") 返回 Ich bin Hamsterchen(而不是 Ich bin Hamchen) - 很好!
    • $currentScriptPath = $MyInvocation.MyCommand.Definition; $currentScriptName = $MyInvocation.MyCommand.Name; $currentScriptDir = $currentScriptPath.Substring(0,$currentScriptPath.IndexOf($currentScriptName));
    【解决方案7】:

    如之前的回复中所述,使用“$MyInvocation”会遇到范围问题,并且不一定提供一致的数据(返回值与直接访问值)。我发现无论范围如何(在主函数或后续/嵌套函数调用中),获取脚本信息(如脚本路径、名称、参数、命令行等)的“最干净”(最一致)的方法是使用“Get- “MyInvocation”上的变量”...

    # Get the MyInvocation variable at script level
    # Can be done anywhere within a script
    $ScriptInvocation = (Get-Variable MyInvocation -Scope Script).Value
    
    # Get the full path to the script
    $ScriptPath = $ScriptInvocation.MyCommand.Path
    
    # Get the directory of the script
    $ScriptDirectory = Split-Path $ScriptPath
    
    # Get the script name
    # Yes, could get via Split-Path, but this is "simpler" since this is the default return value
    $ScriptName = $ScriptInvocation.MyCommand.Name
    
    # Get the invocation path (relative to $PWD)
    # @GregMac, this addresses your second point
    $InvocationPath = ScriptInvocation.InvocationName
    

    因此,您可以获得与 $PSCommandPath 相同的信息,但在交易中可以获得更多信息。不确定,但看起来“Get-Variable”直到 PS3 才可用,因此对于真正旧(未更新)的系统没有太多帮助。

    使用“-Scope”还有一些有趣的方面,因为您可以回溯以获取调用函数的名称等。 0=当前,1=父级,等等。

    希望这有点帮助。

    参考,https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-variable

    【讨论】:

      【解决方案8】:

      我认为有更好的方法,通过设置变量 $MyInvocation.MyCommand.Path 的范围:

      ex> $脚本:MyInvocation.MyCommand.Name

      此方法适用于所有调用情况:

      前: Somescript.ps1

      function printme () {
          "In function:"
          ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
          ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
          ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
      }
      "Main:"
      ( "MyInvocation.ScriptName: " + [string]($MyInvocation.ScriptName) )
      ( "script:MyInvocation.MyCommand.Name: " + [string]($script:MyInvocation.MyCommand.Name) )
      ( "MyInvocation.MyCommand.Name: " + [string]($MyInvocation.MyCommand.Name) )
      " "
      printme
      exit
      

      输出:

      PS> powershell C:\temp\test.ps1
      Main:
      MyInvocation.ScriptName:
      script:MyInvocation.MyCommand.Name: test.ps1
      MyInvocation.MyCommand.Name: test.ps1
      
      In function:
      MyInvocation.ScriptName: C:\temp\test.ps1
      script:MyInvocation.MyCommand.Name: test.ps1
      MyInvocation.MyCommand.Name: printme
      

      请注意,当从 Main 调用时,上述接受的答案如何不返回值。另外,请注意,当问题仅请求脚本名称时,上述接受的答案会返回完整路径。作用域变量适用于所有地方。

      另外,如果您确实想要完整路径,那么您只需调用:

      $script:MyInvocation.MyCommand.Path
      

      【讨论】:

        【解决方案9】:

        @gregmac 的(优秀而详细的)答案的简短演示,基本上推荐 $PSCommandPath 作为返回当前正在运行的使用 Powershell 3.0 及更高版本的脚本的唯一可靠命令。

        这里我显示返回完整路径或只返回文件名。

        Test.ps1:

        'Direct:'
        $PSCommandPath  # Full Path 
        Split-Path -Path $PSCommandPath -Leaf  # File Name only
        
        function main () {
          ''
          'Within a function:'
          $PSCommandPath
          Split-Path -Path $PSCommandPath -Leaf
        }
        
        main
        

        输出:

        PS> .\Test.ps1
        Direct:
        C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1
        Test.ps1
        
        Within a function:
        C:\Users\John\Documents\Sda\Code\Windows\PowerShell\Apps\xBankStatementRename\Test.ps1
        Test.ps1
        

        【讨论】:

          【解决方案10】:

          在 PS 2 和 PS 4 上使用以下脚本进行了一些测试,结果相同。我希望这对人们有所帮助。

          $PSVersionTable.PSVersion
          function PSscript {
            $PSscript = Get-Item $MyInvocation.ScriptName
            Return $PSscript
          }
          ""
          $PSscript = PSscript
          $PSscript.FullName
          $PSscript.Name
          $PSscript.BaseName
          $PSscript.Extension
          $PSscript.DirectoryName
          
          ""
          $PSscript = Get-Item $MyInvocation.InvocationName
          $PSscript.FullName
          $PSscript.Name
          $PSscript.BaseName
          $PSscript.Extension
          $PSscript.DirectoryName
          

          结果 -

          Major  Minor  Build  Revision
          -----  -----  -----  --------
          4      0      -1     -1      
          
          C:\PSscripts\Untitled1.ps1
          Untitled1.ps1
          Untitled1
          .ps1
          C:\PSscripts
          
          C:\PSscripts\Untitled1.ps1
          Untitled1.ps1
          Untitled1
          .ps1
          C:\PSscripts
          

          【讨论】:

            【解决方案11】:

            这适用于大多数 powershell 版本:

            (& { $MyInvocation.ScriptName; })
            

            这适用于计划作业

            Get-ScheduledJob |? Name -Match 'JOBNAMETAG' |% Command
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2019-03-16
              • 1970-01-01
              • 2011-02-07
              • 1970-01-01
              相关资源
              最近更新 更多