这应该是一个简单的任务,但是我已经看到过几次关于如何获取已执行cmdlet所在目录的路径的尝试,结果好坏参半。例如,当我执行C:\temp\myscripts\mycmdlet。我想能够将C:\temp\myscripts存储在mycmdlet.ps1中的一个变量中。

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

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

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

$settingspath = '.\settings.xml'

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


当前回答

I had similar problems and it made me a lot of trouble since I am making programs written in PowerShell (full end user GUI applications) and I have a lot of files and resources I need to load from disk. From my experience, using . to represent current directory is unreliable. It should represent current working directory, but it often does not. It appears that PowerShell saves location from which PowerShell has been invoked inside .. To be more precise, when PowerShell is first started, it starts, by default, inside your home user directory. That is usually directory of your user account, something like C:\USERS\YOUR USER NAME. After that, PowerShell changes directory to either directory from which you invoked it, or to directory where script you are executing is located before either presenting you with PowerShell prompt or running the script. But that happens after PowerShell app itself originally starts inside your home user directory.

And . represents that initial directory inside which PowerShell started. So . only represents current directory in case if you invoked PowerShell from the wanted directory. If you later change directory in PowerShell code, change appears not to be reflected inside . in every case. In some cases . represents current working directory, and in others directory from which PowerShell (itself, not the script) has been invoked, what can lead to inconsistent results. For this reason I use invoker script. PowerShell script with single command inside: POWERSHELL. That will ensure that PowerShell is invoked from the wanted directory and thus make . represent current directory. But it only works if you do not change directory later in PowerShell code. In case of a script, I use invoker script which is similar to last one I mentioned, except it contains a file option: POWERSHELL -FILE DRIVE:\PATH\SCRIPT NAME.PS1. That ensures that PowerShell is started inside current working directory.

只需单击脚本就可以从主用户目录调用PowerShell,而不管脚本位于何处。 它的结果是当前工作目录是脚本所在的目录,但PowerShell调用目录是C:\USERS\YOUR USER NAME,与。根据情况返回这两个目录中的一个,这是荒谬的。

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

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

其他回答

试一试:

(Get-Location).path

or:

($pwd).path

可靠的方法就像您显示的$ myinvoke . mycommand . path一样。

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

PowerShell v3 +:

使用自动变量$PSScriptRoot。

如果你只需要当前目录的名称,你可以这样做:

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

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

输出

MyWorkingDirectory

试试这个:

$WorkingDir = Convert-Path .

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

}