ChatGPT解决这个技术问题 Extra ChatGPT

如何获取正在执行的 cmdlet 的当前目录

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

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

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

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

$settingspath = '.\settings.xml'

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

请注意,这个问题的模棱两可的标题导致下面的答案解决了两个不同的问题之一,而没有明确说明哪个:(a)如何引用当前位置(目录)或(b)如何引用正在运行的脚本的位置(运行脚本所在的目录,可能是也可能不是当前目录)。

a
avi12

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

(Get-Item .).FullName

谢谢,这是从相对路径中找到完整路径的好方法。例如 (Get-Item -Path $myRelativePath -Verbose).FullName
这次真是万分感谢。其他答案不适用于编译为 EXE 的 Powershell 脚本。
这是错误。这将获取 process 的当前目录,该目录可以在任何地方。例如,如果我的命令行当前目录是 C:\mydir,并且我调用命令 C:\dir1\dir2\dir3\mycmdlet.ps1,那么这将解析为 C:\mydir,而不是 C:\dir1\dir2\dir3。调用新的可执行文件也有同样的问题,因为当前目录是从父进程继承的。
像魅力一样工作
J
JasonMArcher

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

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

PowerShell v3+:

使用自动变量 $PSScriptRoot


你能解释一下你是如何找到财产路径的吗? $MyInvocation.MyCommand|gm 不在成员列表中显示此类属性。
为什么不直接使用 $PSScriptRoot?似乎更可靠
@user2326106 你能解释一下 $PSScriptRoot$MyInvocation.MyCommand.Path 之间的区别吗?
@VitaliyMarkitanov 您是否在脚本中运行了 $MyInvocation.MyCommand | gmPath是脚本文件的全路径,直接在终端执行是找不到的。
我在使用 $MyInvocation.MyCommand.Path\File.csv & 时遇到了问题在我用谷歌搜索 $MyInvocation.MyCommand.Path 后,我发现了这个 MS article 的详细信息,我不得不将其中的一部分拆分出来 &在我让它工作之前放入变量: $myDir = Split-Path -Parent $MyInvocation.MyCommand.Path 。对powershell非常新,所以问题可能是我缺乏理解
L
Lance U. Matthews

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

 $PSScriptRoot

about_Automatic_Variablesabout_Scripts 都表示:

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

我这样使用它:

 $MyFileName = "data.txt"
 $filebase = Join-Path $PSScriptRoot $MyFileName

它是特定于版本的。这至少需要 Powershell 3.0。
这就是我需要引用与脚本位于同一位置的文件的内容——谢谢!
这是最好的答案,因为它准确地为您提供了 PS 脚本所在的路径,该路径本质上是脚本执行的根目录。它不关心您调用脚本的当前工作目录是什么。 +1。
@MarvinDickhaus 这就是为什么需要在大多数脚本中使用“Set-StrictMode -Version 3.0”的原因:) 非常感谢链接!
A
Alex Angas

您还可以使用:

(Resolve-Path .\).Path

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

(自 PowerShell 2.0 起可用。)


这是错误。这将获取 process 的当前目录,该目录可以在任何地方。例如,如果我的命令行当前目录是 C:\mydir,并且我调用命令 C:\dir1\dir2\dir3\mycmdlet.ps1,那么这将解析为 C:\mydir,而不是 C:\dir1\dir2\dir3。调用新的可执行文件也有同样的问题,因为当前目录是从父进程继承的。
谢谢!我也误解了这个问题的标题,这个答案正是我想要的。但是......它没有回答这个问题。
N
Nae

尝试 :

(Get-Location).path

或者:

($pwd).path

每当我从 powershell 中休息很长时间时,我都会忘记 $pwd/$PWD!更有用的IMO...
C
Christian Flem

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

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("\"));
    }
}

为什么-范围1?不是 - 范围 0
Get-Variable :范围编号“1”超过了活动范围的数量。
您收到此错误是因为您没有父范围。 -Scope 参数获取指定范围内的变量。在这种情况下,1 是父范围。有关详细信息,请参阅有关 Get-Variable ( technet.microsoft.com/en-us/library/hh849899.aspx ) 的 technet 文章
P
Peter Mortensen

Get-Location 将返回当前位置:

$Currentlocation = Get-Location

PS C:\Windows\system32> C:\powershell\checkfile.ps1 --> 这将给出 c:\windows\system32
P
Peter Mortensen

我喜欢the one-line solution :)

$scriptDir = Split-Path -Path $MyInvocation.MyCommand.Definition -Parent

是的,对我有用。我的密码是我的用户目录,我在另一个目录(B)中运行脚本(B)
M
Mohammad

尝试这个:

$WorkingDir = Convert-Path .

B
BlackSpy

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

$PSScriptRoot


S
SolThoth

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

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

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

输出

我的工作目录


S
SteinarV

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

PS-ISE(PowerShell ISE)

VS 代码(Visual Studio 代码)

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

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

$directorypath = if ($PSScriptRoot) { $PSScriptRoot } `
    elseif ($psise) { split-path $psise.CurrentFile.FullPath } `
    elseif ($psEditor) { split-path $psEditor.GetEditorContext().CurrentFile.Path }

这是我发现在 PowerShell ISE 和 VS Code 中都可以使用的唯一选项。
P
Peter Mortensen

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

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

末尾的 1 是忽略 /

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


f
freakydinde

此函数将提示位置设置为脚本路径,处理在 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 }
}

s
syanzy

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


z
zman

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

@((
  ($MyInvocation.MyCommand.Module.ModuleBase),
  ($PSScriptRoot),
  (Split-Path -Parent -Path $MyInvocation.MyCommand.Definition -ErrorAction SilentlyContinue),
  (Get-Location | Select-Object -ExpandProperty Path)
) | Where-Object { $_ })[0]

o
ouflak

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

(Split-Path -Path (Get-Location) -Leaf)

E
Erutan409

要扩展 @Cradle 的答案:您还可以编写一个 multi-purpose function 来根据 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
    }

}

S
SYOB SYOT

我遇到了类似的问题,这给我带来了很多麻烦,因为我正在制作用 PowerShell(完整的最终用户 GUI 应用程序)编写的程序,并且我有很多文件和资源需要从磁盘加载。根据我的经验,使用 . 表示当前目录是不可靠的。它应该代表当前工作目录,但通常不代表。 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 新)。


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅