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

时间:2011-12-01 15:23:53

标签: powershell cmdlet

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

这是一个有效的解决方案(虽然有点麻烦):

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

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

$settingspath = '.\settings.xml'

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

18 个答案:

答案 0 :(得分:231)

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

(Get-Item -Path ".\").FullName

答案 1 :(得分:114)

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

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

答案 2 :(得分:77)

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

 $PSScriptRoot

about_Automatic_Variablesabout_Scripts都声明:

  

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

我这样用:

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

答案 3 :(得分:42)

您也可以使用:

(Resolve-Path .\).Path

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

(自PowerShell 2.0起可用。)

答案 4 :(得分:32)

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

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

答案 5 :(得分:24)

尝试:

(Get-Location).path

或:

($pwd).path

答案 6 :(得分:15)

Get-Location将返回当前位置:

$Currentlocation=Get-Location

答案 7 :(得分:11)

我喜欢一行solution:)

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

答案 8 :(得分:9)

试试这个:

$WorkingDir = Convert-Path .

答案 9 :(得分:3)

在Powershell 3及以上版本中,您只需使用

即可

$PSScriptRoot

答案 10 :(得分: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 }
}

答案 11 :(得分:2)

在以下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 }

答案 12 :(得分:1)

你会认为使用'。\'作为路径意味着它是调用路径。但不是所有的时间。例如,如果您在作业ScriptBlock中使用它。在这种情况下,它可能指向%profile%\ Documents。

答案 13 :(得分:1)

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

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

答案 14 :(得分:0)

要扩展@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
    }

}

答案 15 :(得分:0)

对于一个解决方案而言,以下是对我有用的解决方案。

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

最后的1是忽略/。

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

答案 16 :(得分:0)

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

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

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

输出

MyWorkingDirectory

答案 17 :(得分:0)

我也遇到了类似的问题,这使我很麻烦,因为我正在编写用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更高)中使用。