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

发布于 2024-10-27 22:49:45 字数 350 浏览 3 评论 0原文

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

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

$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

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

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

Whenever I need to reference a common module or script, I like to use paths relative to the current script file. That way, my script can always find other scripts in the library.

So, what is the best, standard way of determining the directory of the current script? Currently, I'm doing:

$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)

I know in modules (.psm1) you can use $PSScriptRoot to get this information, but that doesn't get set in regular scripts (i.e. .ps1 files).

What's the canonical way to get the current PowerShell script file's location?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(14

浅唱々樱花落 2024-11-03 22:49:45

PowerShell 3+

# This is an automatic variable set to the current file's/module's directory
$PSScriptRoot

PowerShell 2

在 PowerShell 3 之前,没有比查询更好的方法
通用脚本的 MyInspiration.MyCommand.Definition 属性。基本上我拥有的每个 PowerShell 脚本的顶部都有以下行:

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition

PowerShell 3+

# This is an automatic variable set to the current file's/module's directory
$PSScriptRoot

PowerShell 2

Prior to PowerShell 3, there was not a better way than querying the
MyInvocation.MyCommand.Definition property for general scripts. I had the following line at the top of essentially every PowerShell script I had:

$scriptPath = split-path -parent $MyInvocation.MyCommand.Definition
江城子 2024-11-03 22:49:45

如果您正在创建 V2 模块,则可以使用名为的自动变量
$PSScriptRoot

来自PS>帮助自动变量

$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.

If you are creating a V2 Module, you can use an automatic variable called
$PSScriptRoot.

From PS > Help 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.
各空 2024-11-03 22:49:45

对于 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.

则函数为:

function Get-ScriptDirectory {
    Split-Path -Parent $PSCommandPath
}

For 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.

The function is then:

function Get-ScriptDirectory {
    Split-Path -Parent $PSCommandPath
}
小忆控 2024-11-03 22:49:45

对于 PowerShell 3+,

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

我已将此函数放在我的个人资料中。它也可以在 ISE 中使用 F8/Run Selection 运行。

For PowerShell 3+

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

I've placed this function in my profile. It works in ISE using F8/Run Selection too.

揪着可爱 2024-11-03 22:49:45

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

除非你指的是这样的事情,我在再次阅读问题后明白了这一点。

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

Maybe I'm missing something here... but if you want the present working directory you can just use this: (Get-Location).Path for a string, or Get-Location for an object.

Unless you're referring to something like this, which I understand after reading the question again.

function Get-Script-Directory
{
    $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
    return Split-Path $scriptInvocation.MyCommand.Path
}
寄与心 2024-11-03 22:49:45

我使用 自动变量 $执行上下文
它将在 PowerShell 2 及更高版本中运行。

 $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')

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

I use the automatic variable $ExecutionContext.
It will work from PowerShell 2 and later.

 $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')

$ExecutionContext
Contains an EngineIntrinsics object that represents the
execution context of the Windows PowerShell host. You can
use this variable to find the execution objects that are
available to cmdlets.

深陷 2024-11-03 22:49:45

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

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
}

Using pieces from all of these answers and the comments, I put this together for anyone who sees this question in the future. It covers all of the situations listed in the other answers, and I've added another one I found as a fail-safe.

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
}
水水月牙 2024-11-03 22:49:45

与已经发布的答案非常相似,但管道似乎更像 PowerShell:

$PSCommandPath | Split-Path -Parent

Very similar to already posted answers, but piping seems more PowerShell-like:

$PSCommandPath | Split-Path -Parent
何以笙箫默 2024-11-03 22:49:45

我花了一段时间才开发出一些东西,将接受的答案变成一个强大的功能。

我不确定其他人的情况,但我在使用 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
}

这也意味着该函数引用脚本范围而不是 Michael Sorens 在他的一篇博客文章中。

It took me a while to develop something that took the accepted answer and turned it into a robust function.

I am not sure about others, but I work in an environment with machines on both PowerShell version 2 and 3, so I needed to handle both. The following function offers a graceful fallback:

Function Get-PSScriptRoot
{
    $ScriptRoot = ""

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

    Write-Output $ScriptRoot
}

It also means that the function refers to the Script scope rather than the parent's scope as outlined by Michael Sorens in one of his blog posts.

清泪尽 2024-11-03 22:49:45

我总是使用这个适用于 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

I always use this little snippet which works for PowerShell and ISE the same way :

# 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
葵雨 2024-11-03 22:49:45

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

当从主脚本和导入的 .PSM1 库文件的主行调用时,将“$global:”前缀添加到 MyInitation 结构将返回完整路径和脚本名称。它还可以在导入库的函数内工作。

经过多次摆弄后,我决定使用 $global:MyInitation.InvocableName。
它可以与 CMD 启动、Run With Powershell 和 ISE 一起可靠地工作。
本地和 UNC 启动都会返回正确的路径。

I needed to know the script name and where it is executing from.

Prefixing "$global:" to the MyInvocation structure returns the full path and script name when called from both the main script, and the main line of an imported .PSM1 library file. It also works from within a function in an imported library.

After much fiddling around, I settled on using $global:MyInvocation.InvocationName.
It works reliably with CMD launch, Run With Powershell, and the ISE.
Both local and UNC launches return the correct path.

临走之时 2024-11-03 22:49:45

如果要从相对于脚本运行位置的路径加载模块,例如从“lib”子文件夹”,则需要使用以下之一:

$PSScriptRoot,当作为脚本,例如通过 PowerShell 命令
$psISE.CurrentFile.FullPath 当您在 ISE 中运行时有效,

但是如果您两者都不在,并且只是在 PowerShell shell 中输入,则可以使用:

pwd.Path< /code>

您可以根据您运行的环境将这三个变量之一分配给名为 $base 的变量,如下所示:

$base=$(if ($psISE) {Split-Path -Path $psISE.CurrentFile.FullPath} else {$(if ($global:PSScriptRoot.Length -gt 0) {$global:PSScriptRoot} else {$global:pwd.Path})})

然后在您的脚本中,您可以像这样使用它:

Import-Module $base\lib\someConstants.psm1
Import-Module $base\lib\myCoolPsModule1.psm1
#etc.

If you want to load modules from a path relative to where the script runs, such as from a "lib" subfolder", you need to use one of the following:

$PSScriptRoot which works when invoked as a script, such as via the PowerShell command
$psISE.CurrentFile.FullPath which works when you're running inside ISE

But if you're in neither, and just typing away within a PowerShell shell, you can use:

pwd.Path

You can could assign one of the three to a variable called $base depending on the environment you're running under, like so:

$base=$(if ($psISE) {Split-Path -Path $psISE.CurrentFile.FullPath} else {$(if ($global:PSScriptRoot.Length -gt 0) {$global:PSScriptRoot} else {$global:pwd.Path})})

Then in your scripts, you can use it like so:

Import-Module $base\lib\someConstants.psm1
Import-Module $base\lib\myCoolPsModule1.psm1
#etc.
乖乖 2024-11-03 22:49:45

如果任何其他方法失败,您也可以考虑 split-path -parent $psISE.CurrentFile.Fullpath。特别是,如果您运行一个文件来加载一堆函数,然后在 ISE shell 中执行这些函数(或者如果您运行选择),则似乎是 Get-Script-Directory 函数如上所述不起作用。

You might also consider split-path -parent $psISE.CurrentFile.Fullpath if any of the other methods fail. In particular, if you run a file to load a bunch of functions and then execute those functions with-in the ISE shell (or if you run-selected), it seems the Get-Script-Directory function as above doesn't work.

绅刃 2024-11-03 22:49:45

我发现此处发布的旧解决方案在 PowerShell V5 上对我不起作用。我想出了这个:

try {
    $scriptPath = $PSScriptRoot
    if (!$scriptPath)
    {
        if ($psISE)
        {
            $scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
        }
        else {
            Write-Host -ForegroundColor Red "Cannot resolve script file's path"
            exit 1
        }
    }
}
catch {
    Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
    exit 2
}

Write-Host "Path: $scriptPath"

I found that the older solutions posted here didn't work for me on PowerShell V5. I came up with this:

try {
    $scriptPath = $PSScriptRoot
    if (!$scriptPath)
    {
        if ($psISE)
        {
            $scriptPath = Split-Path -Parent -Path $psISE.CurrentFile.FullPath
        }
        else {
            Write-Host -ForegroundColor Red "Cannot resolve script file's path"
            exit 1
        }
    }
}
catch {
    Write-Host -ForegroundColor Red "Caught Exception: $($Error[0].Exception.Message)"
    exit 2
}

Write-Host "Path: $scriptPath"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文