233

这应该是一个简单的任务,但我已经看到了几次尝试如何获取执行的 cmdlet 所在目录的路径,但成功率参差不齐。例如,当我执行C:\temp\myscripts\mycmdlet.ps1其中有一个设置文件时,C:\temp\myscripts\settings.xml我希望能够存储C:\temp\myscriptsmycmdlet.ps1.

这是一种可行的解决方案(虽然有点麻烦):

$invocation = (Get-Variable MyInvocation).Value
$directorypath = Split-Path $invocation.MyCommand.Path
$settingspath = $directorypath + '\settings.xml'

另一个人建议这个解决方案只适用于我们的测试环境:

$settingspath = '.\settings.xml'

我非常喜欢后一种方法,并且更喜欢它每次都必须将文件路径解析为参数,但我无法让它在我的开发环境中工作。我该怎么办?它与PowerShell的配置方式有关吗?

4

19 回答 19

288

是的,这应该有效。但是,如果您需要查看绝对路径,这就是您所需要的:

(Get-Item .).FullName
于 2014-04-17T11:30:21.863 回答
178

执行此操作的可靠方法就像您展示的那样$MyInvocation.MyCommand.Path

使用相对路径将基于 $pwd、在 PowerShell 中、应用程序的当前目录或 .NET API 的当前工作目录。

PowerShell v3+

使用自动变量$PSScriptRoot

于 2011-12-06T21:15:05.573 回答
89

最简单的方法似乎是使用以下预定义变量:

 $PSScriptRoot

about_Automatic_Variables并且about_Scripts都声明:

在 PowerShell 2.0 中,此变量仅在脚本模块 (.psm1) 中有效。从 PowerShell 3.0 开始,它在所有脚本中都有效。

我这样使用它:

 $MyFileName = "data.txt"
 $filebase = Join-Path $PSScriptRoot $MyFileName
于 2014-09-24T16:05:57.947 回答
46

您还可以使用:

(Resolve-Path .\).Path

括号中的部分返回一个PathInfo对象。

(自 PowerShell 2.0 起可用。)

于 2015-05-27T02:23:38.833 回答
39

尝试 :

(Get-Location).path

或者:

($pwd).path
于 2016-01-10T08:51:02.047 回答
33

路径通常为空。这个功能更安全。

function Get-ScriptDirectory
{
    $Invocation = (Get-Variable MyInvocation -Scope 1).Value;
    if($Invocation.PSScriptRoot)
    {
        $Invocation.PSScriptRoot;
    }
    Elseif($Invocation.MyCommand.Path)
    {
        Split-Path $Invocation.MyCommand.Path
    }
    else
    {
        $Invocation.InvocationName.Substring(0,$Invocation.InvocationName.LastIndexOf("\"));
    }
}
于 2013-10-23T13:08:53.873 回答
22

Get-Location将返回当前位置:

$Currentlocation = Get-Location
于 2017-03-09T16:09:02.007 回答
12

我喜欢单线解决方案:)

$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent
于 2015-12-17T12:44:23.227 回答
9

试试这个:

$WorkingDir = Convert-Path .
于 2017-06-21T17:58:58.833 回答
5

在 Powershell 3 及更高版本中,您可以简单地使用

$PSScriptRoot

于 2018-05-03T04:43:43.480 回答
4

如果您只需要当前目录的名称,则可以执行以下操作:

((Get-Location) | Get-Item).Name

假设您在 C:\Temp\Location\MyWorkingDirectory> 工作

输出

我的工作目录

于 2019-09-12T02:16:02.790 回答
4

在以下 IDE 中调试时,大多数答案都不起作用:

  • PS-ISE(PowerShell ISE)
  • VS 代码(Visual Studio 代码)

因为在那些$PSScriptRoot是空的并且Resolve-Path .\(和类似的)将导致不正确的路径。

Freakydinde 的答案是唯一可以解决这些情况的答案,所以我对此表示赞同,但我认为该Set-Location答案中的答案并不是真正需要的。所以我解决了这个问题并使代码更清晰:

$directorypath = if ($PSScriptRoot) { $PSScriptRoot } `
    elseif ($psise) { split-path $psise.CurrentFile.FullPath } `
    elseif ($psEditor) { split-path $psEditor.GetEditorContext().CurrentFile.Path }
于 2020-06-27T01:04:27.217 回答
2

对于它的价值,作为单行解决方案,以下是我的工作解决方案。

$currFolderName = (Get-Location).Path.Substring((Get-Location).Path.LastIndexOf("\")+1)

最后的 1 是忽略/.

感谢上面使用Get-Location cmdlet 的帖子。

于 2019-03-02T00:13:46.477 回答
2

此函数将提示位置设置为脚本路径,处理在 vscode、psise 和 pwd 之间获取脚本路径的不同方式:

function Set-CurrentLocation
{
    $currentPath = $PSScriptRoot                                                                                                     # AzureDevOps, Powershell
    if (!$currentPath) { $currentPath = Split-Path $pseditor.GetEditorContext().CurrentFile.Path -ErrorAction SilentlyContinue }     # VSCode
    if (!$currentPath) { $currentPath = Split-Path $psISE.CurrentFile.FullPath -ErrorAction SilentlyContinue }                       # PsISE

    if ($currentPath) { Set-Location $currentPath }
}
于 2020-02-19T12:12:30.603 回答
1

你会认为使用'.\'作为路径意味着它是调用路径。但并非总是如此。例如,如果您在作业 ScriptBlock 中使用它。在这种情况下,它可能指向 %profile%\Documents。

于 2013-12-06T13:05:38.273 回答
1

这就是我想出的。它是一个数组,包含多种查找路径的方法,使用当前位置,过滤掉 null\empty 结果,并返回第一个非 null 值。

@((
  ($MyInvocation.MyCommand.Module.ModuleBase),
  ($PSScriptRoot),
  (Split-Path -Parent -Path $MyInvocation.MyCommand.Definition -ErrorAction SilentlyContinue),
  (Get-Location | Select-Object -ExpandProperty Path)
) | Where-Object { $_ })[0]
于 2021-07-16T13:18:36.693 回答
1

要仅获取当前文件夹名称,您还可以使用:

(Split-Path -Path (Get-Location) -Leaf)
于 2021-11-21T00:08:35.090 回答
-1

要扩展 @Cradle 的答案:您还可以编写一个多功能函数,根据 OP 的问题为您提供相同的结果:

Function Get-AbsolutePath {

    [CmdletBinding()]
    Param(
        [parameter(
            Mandatory=$false,
            ValueFromPipeline=$true
        )]
        [String]$relativePath=".\"
    )

    if (Test-Path -Path $relativePath) {
        return (Get-Item -Path $relativePath).FullName -replace "\\$", ""
    } else {
        Write-Error -Message "'$relativePath' is not a valid path" -ErrorId 1 -ErrorAction Stop
    }

}
于 2016-01-16T23:05:05.837 回答
-1

我遇到了类似的问题,这给我带来了很多麻烦,因为我正在制作用 PowerShell(完整的最终用户 GUI 应用程序)编写的程序,并且我有很多文件和资源需要从磁盘加载。根据我的经验,.用来表示当前目录是不可靠的。它应该代表当前工作目录,但通常不代表。看来 PowerShell 保存了在 PowerShell 中调用 PowerShell 的位置.。更准确地说,当 PowerShell 首次启动时,默认情况下,它会在您的主用户目录中启动。这通常是您的用户帐户的目录,例如C:\USERS\YOUR USER NAME. 之后,PowerShell 将目录更改为您调用它的目录,或者更改为您正在执行的脚本所在的目录,然后再向您显示 PowerShell 提示符或运行脚本。但这发生在 PowerShell 应用程序本身最初在您的主用户目录中启动之后。

.表示 PowerShell 在其中启动的初始目录。因此,.仅代表当前目录,以防您从所需目录调用 PowerShell。如果您稍后在 PowerShell 代码中更改目录,则更改似乎不会.在每种情况下都反映在内部。在某些情况下.代表当前工作目录,而在其他目录中,PowerShell(本身,而不是脚本)已被调用,这会导致结果不一致。出于这个原因,我使用调用程序脚本。PowerShell 脚本,其中包含单个命令: POWERSHELL. 这将确保从所需目录调用 PowerShell,从而使.代表当前目录。但它仅在您稍后不在 PowerShell 代码中更改目录时才有效。在脚本的情况下,我使用类似于我提到的最后一个的调用程序脚本,除了它包含一个文件选项: POWERSHELL -FILE DRIVE:\PATH\SCRIPT NAME.PS1. 这确保 PowerShell 在当前工作目录中启动。

无论脚本位于何处,只需单击脚本即可从您的主用户目录调用 PowerShell。它导致当前工作目录是脚本所在的目录,但 PowerShell 调用目录是C:\USERS\YOUR USER NAME,并且.根据情况返回这两个目录之一,这是荒谬的。

但是为了避免所有这些大惊小怪并使用调用程序脚本,您可以简单地使用$PWD$PSSCRIPTROOT代替.表示当前目录,具体取决于您希望表示当前工作目录或调用脚本的目录的天气。如果您出于某种原因想要检索.返回的两个目录中的另一个,您可以使用$HOME.

我个人只是在我使用 PowerShell 开发的应用程序的根目录中有调用程序脚本,它调用我的主应用程序脚本,并且只记得永远不要更改我的应用程序源代码中的当前工作目录,所以我永远不必担心这个,我可以.用来表示当前目录并在我的应用程序中支持相对文件寻址而没有任何问题。这应该适用于较新版本的 PowerShell(比版本 2 新)。

于 2019-11-03T17:26:12.163 回答