确定当前PowerShell脚本位置的最佳方法是什么?

Aar*_*sen 492 powershell powershell-2.0

每当我需要引用一个公共模块或脚本时,我喜欢使用相对于当前脚本文件的路径,这样,我的脚本总能找到库中的其他脚本.

那么,确定当前脚本目录的最佳标准方法是什么?目前,我正在做:

$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
Run Code Online (Sandbox Code Playgroud)

我知道在模块(.psm1)中你可以使用它$PSScriptRoot来获取这些信息,但这不会在常规脚本(即.ps1文件)中设置.

获取当前PowerShell脚本文件位置的规范方法是什么?

Jar*_*Par 804

PowerShell 3+

# This is an automatic variable set to the current file's/module's directory
$PSScriptRoot
Run Code Online (Sandbox Code Playgroud)

PowerShell 2

在PowerShell 3之前,没有比查询MyInvocation.MyCommand.Definition常规脚本属性更好的方法了 .我在基本上每个PowerShell脚本的顶部都有以下行:

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
Run Code Online (Sandbox Code Playgroud)

  • `Split-Path`与`-Parent`参数一起使用,返回当前目录而不执行当前正在执行的脚本名称. (6认同)
  • 狡辩一下可能有趣的事情:`$PSScriptRoot` 更接近的 v2- 近似值是(`Split-Path -Parent` 应用于)`$MyInitation.MyCommand.Path`,而不是 `$MyInitation.MyCommand.Definition`,尽管在它们的行为相同的脚本的顶级范围(这是为此目的唯一明智的调用位置)。当在_function_或_script block_内部调用时,前者返回空字符串,而后者返回函数体/脚本块的_definition_作为字符串(一段PowerShell源代码)。 (5认同)
  • 注意:对于Linux/macOS上的PowerShell,您的脚本必须具有.ps1扩展名,以便填充PSScriptRoot/MyInvocation等.请参阅此处的错误报告:https://github.com/PowerShell/PowerShell/issues/4217 (4认同)

And*_*der 60

如果要创建V2模块,可以使用名为的自动变量 $PSScriptRoot.

从PS>帮助automatic_variable

$PSScriptRoot
       Contains the directory from which the script module is being executed.
       This variable allows scripts to use the module path to access other
       resources.

  • 这就是PS 3.0中所需要的:`$ PSCommandPath包含正在运行的脚本的完整路径和文件名.此变量在所有脚本中都有效 (12认同)
  • v2中的@user $ PSScriptRoot仅适用于*modules*,如果您正在编写"普通"脚本而不是需要$ MyInvocation.MyCommand.Definition的模块,请参阅最佳答案. (5认同)
  • 我糊涂了.这个答案说使用PSScriptRoot for V2.另一个答案说PSScriptRoot适用于V3 +,并且使用不同的v2. (4认同)
  • 刚刚测试了$ PSScriptRoot并按预期工作。但是,如果在命令行中运行它,它将为您提供一个空字符串。如果在脚本中使用并且执行了脚本,它只会给您结果。那就是...的意思。 (2认同)

Cod*_*ing 30

适用于PowerShell 3.0

$PSCommandPath
    Contains the full path and file name of the script that is being run. 
    This variable is valid in all scripts.
Run Code Online (Sandbox Code Playgroud)

那么功能是:

function Get-ScriptDirectory {
    Split-Path -Parent $PSCommandPath
}
Run Code Online (Sandbox Code Playgroud)

  • 更好的是,使用$ PSScriptRoot.它是当前文件的/模块目录. (17认同)
  • 该命令包括脚本的文件名,这使我不知所措。当您需要路径时,您可能也不想在其中使用脚本名称。至少,我想不出您想要的理由。$ PSScriptRoot不包含文件名(从其他答案中收集)。 (2认同)
  • 常规 PS1 脚本中的 $PSScriptRoot 为空。不过,$PSCommandPath 可以工作。根据其他帖子中给出的描述,两者的行为都是预期的。也可以只使用 [IO.Path]::GetDirectoryName($PSCommandPath) 来获取不带文件名的脚本目录。 (2认同)

nic*_*kzl 17

对于Powershell 3+

function Get-ScriptDirectory {
    if ($psise) {
        Split-Path $psise.CurrentFile.FullPath
    }
    else {
        $global:PSScriptRoot
    }
}
Run Code Online (Sandbox Code Playgroud)

我已将此功能放在我的个人资料中.也可以使用F8/Run Selection在ISE中运行.


Sea*_* C. 14

也许我在这里遗漏了一些东西......但是如果你想要现在的工作目录,你可以使用它:(Get-Location).Path用于字符串或Get-Location对象.

除非你指的是这样的东西,我在再次阅读这个问题后理解这一点.

function Get-Script-Directory
{
    $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
    return Split-Path $scriptInvocation.MyCommand.Path
}
Run Code Online (Sandbox Code Playgroud)

  • 这将获取用户运行脚本**的当前位置**.不是脚本文件**本身的位置**. (16认同)
  • `function Get-Script-Directory {$ scriptInvocation =(Get-Variable MyInvocation -Scope 1).Value return Split-Path $ scriptInvocation.MyCommand.Path} $ hello ="hello"Write-Host(Get-Script-Directory)Write -Host $ hello`保存并从不同的目录运行它.您将显示脚本的路径. (2认同)
  • 注意:此函数的调用必须位于脚本的顶层,如果它嵌套在另一个函数中,则必须更改"-Scope"参数以指定调用堆栈的深度. (2认同)

小智 11

非常类似于已经发布的答案,但管道似乎更像PS.

$PSCommandPath | Split-Path -Parent
Run Code Online (Sandbox Code Playgroud)


小智 10

我使用自动变量 $ ExecutionContext,它适用于PowerShell 2及更高版本.

__PRE__

$ ExecutionContext包含一个EngineIntrinsics对象,该对象表示Windows PowerShell主机的执行上下文.您可以使用此变量来查找cmdlet可用的执行对象.

  • 这显然是在选择工作目录 - 而不是脚本所在的位置? (2认同)
  • @monojohnny 是的,这基本上是当前工作目录,从其他位置调用脚本时将不起作用。 (2认同)

Ran*_*ndy 10

我使用所有这些答案和评论中的片段,将其放在一起,供将来看到这个问题的任何人使用。它涵盖了其他答案中列出的所有情况,并且我添加了我发现的另一种情况作为故障保护。

function Get-ScriptPath()
{
    # If using PowerShell ISE
    if ($psISE)
    {
        $ScriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
    }
    # If using PowerShell 3.0 or greater
    elseif($PSVersionTable.PSVersion.Major -gt 3)
    {
        $ScriptPath = $PSScriptRoot
    }
    # If using PowerShell 2.0 or lower
    else
    {
        $ScriptPath = split-path -parent $MyInvocation.MyCommand.Path
    }

    # If still not found
    # I found this can happen if running an exe created using PS2EXE module
    if(-not $ScriptPath) {
        $ScriptPath = [System.AppDomain]::CurrentDomain.BaseDirectory.TrimEnd('\')
    }

    # Return result
    return $ScriptPath
}
Run Code Online (Sandbox Code Playgroud)


Bru*_*uno 8

花了一些时间来开发一些能够接受已接受答案的东西并将其变成一个强大的功能.

不确定其他人,但我在PowerShell版本2和3上的机器环境中工作,所以我需要处理这两个.以下功能提供了优雅的后备:

Function Get-PSScriptRoot
{
    $ScriptRoot = ""

    Try
    {
        $ScriptRoot = Get-Variable -Name PSScriptRoot -ValueOnly -ErrorAction Stop
    }
    Catch
    {
        $ScriptRoot = Split-Path $script:MyInvocation.MyCommand.Path
    }

    Write-Output $ScriptRoot
}
Run Code Online (Sandbox Code Playgroud)

它还意味着该函数指的是脚本范围而不是Michael Sorens在其博客中概述的父母范围


Bru*_*vin 7

我需要知道脚本名称及其执行位置.

将"$ global:"前缀添加到MyInvocation结构时,将从主脚本和导入的.PSM1库文件的主线调用时返回完整路径和脚本名称.它也可以在导入库的函数内部工作.

经过多次摆弄后,我决定使用$ global:MyInvocation.InvocationName.它可靠地运行CMD,Run With Powershell和ISE.本地和UNC发射都返回正确的路径.

  • **Split-Path -Path $($ global:MyInvocation.MyCommand.Path)**非常感谢.其他解决方案返回了调用应用程序的路径. (4认同)

Car*_*ten 5

我总是使用这个小片段,以相同的方式适用于PowerShell和ISE

# Set active path to script-location:
$path = $MyInvocation.MyCommand.Path
if (!$path) {
    $path = $psISE.CurrentFile.Fullpath
}
if ($path) {
    $path = Split-Path $path -Parent
}
Set-Location $path
Run Code Online (Sandbox Code Playgroud)