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

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

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

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

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

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

694835 次浏览

PowerShell 3+

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

PowerShell 2

在PowerShell 3之前,没有比查询 MyInvocation.MyCommand.Definition属性用于一般脚本。我在每个PowerShell脚本的顶部都有以下一行:

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

也许我遗漏了什么…但是如果你想要当前的工作目录,你可以使用这个:(Get-Location).Path表示字符串,Get-Location表示对象。

除非你指的是这样的事情,我再看了一遍问题后就明白了。

function Get-Script-Directory
{
$scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
return Split-Path $scriptInvocation.MyCommand.Path
}
如果您正在创建V2模块,您可以使用名为 # EYZ0。< / p >

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

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

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
}

我需要知道脚本名称以及它在哪里执行。

给MyInvocation结构加上前缀“$global:”,当从主脚本和导入的. psm1库文件的主线调用时,将返回完整的路径和脚本名称。它也可以在导入库中的函数中工作。

经过大量的摆弄,我决定使用$global: myinvoke . invocationname。 它可靠地工作与CMD启动,运行与Powershell,和ISE。 本地和UNC启动都返回正确的路径
function func1()
{
$inv = (Get-Variable MyInvocation -Scope 1).Value
#$inv.MyCommand | Format-List *
$Path1 = Split-Path $inv.scriptname
Write-Host $Path1
}


function Main()
{
func1
}


Main

我使用自动变量 $ExecutionContext。 它将在PowerShell 2和更高版本中工作

 $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')
< p > ExecutionContext美元 对象的engineintrinsic对象 Windows PowerShell主机的执行上下文。你可以 使用此变量查找执行对象

我花了一段时间来开发一些东西,把接受的答案变成一个健壮的函数。

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

这也意味着函数引用Script作用域,而不是Michael Sorens 在他的一篇博客文章中所概述的父作用域。

非常类似于已经发布的答案,但管道似乎更像powershell:

$PSCommandPath | Split-Path -Parent

对于PowerShell 3+

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

我在我的配置文件中放置了这个函数。它也可以在ISE中使用F8/运行选择。

我发现这里发布的旧解决方案在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"

我总是使用这个小片段,它适用于PowerShell和伊势:

# 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

从所有这些回答和评论中,我把这些问题整理在一起,供将来看到这个问题的人参考。它涵盖了其他答案中列出的所有情况,我添加了另一个我发现的故障保险。

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
}

如果您想从相对于脚本运行位置的路径加载模块,例如从"lib"子文件夹时,您需要使用以下其中之一:

$PSScriptRoot,当作为脚本调用时,例如通过PowerShell命令 $psISE.CurrentFile.FullPath,当你运行在ISE

但如果你都不在PowerShell中,只是在PowerShell中输入,你可以使用:

# EYZ0

你可以根据你所运行的环境将其中一个变量赋值为$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.