每当我需要引用一个通用模块或脚本时,我喜欢使用相对于当前脚本文件的路径。这样,我的脚本总能在库中找到其他脚本。
那么,确定当前脚本目录的最佳标准方法是什么?目前,我正在做:
$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
我知道在模块 (.psm1) 中您可以使用 $PSScriptRoot
来获取此信息,但这不会在常规脚本(即 .ps1 文件)中设置。
获取当前 PowerShell 脚本文件位置的规范方法是什么?
# 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
如果您要创建 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.
$PSCommandPath Contains the full path and file name of the script that is being run. This variable is valid in all scripts.
对于 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
}
适用于 PowerShell 3+
function Get-ScriptDirectory {
if ($psise) {
Split-Path $psise.CurrentFile.FullPath
}
else {
$global:PSScriptRoot
}
}
我已将此功能放在我的个人资料中。它也可以在 ISE 中使用 F8/运行选择。
$script:PSScriptRoot
而不是 $global:PSScriptRoot
,它仅适用于 ISE,但不适用于普通 PowerShell。
也许我在这里遗漏了一些东西......但是如果您想要当前的工作目录,您可以使用:(Get-Location).Path
用于字符串,或 Get-Location
用于对象。
除非你指的是这样的东西,我在再次阅读问题后理解。
function Get-Script-Directory
{
$scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
return Split-Path $scriptInvocation.MyCommand.Path
}
function Get-Script-Directory { $scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value return Split-Path $scriptInvocation.MyCommand.Path } $hello = "hello" Write-Host (Get-Script-Directory) Write-Host $hello
保存并从不同的目录运行它。您将显示脚本的路径。
我使用 automatic variable $ExecutionContext
。它适用于 PowerShell 2 及更高版本。
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')
$ExecutionContext 包含一个 EngineIntrinsics 对象,该对象表示 Windows PowerShell 主机的执行上下文。您可以使用此变量来查找可用于 cmdlet 的执行对象。
与已经发布的答案非常相似,但管道似乎更像 PowerShell:
$PSCommandPath | Split-Path -Parent
$PSScriptRoot
已经有一个自动变量时,为什么要这样做? $PSCommandPath
& $PSScriptRoot
都是在 PowerShell v3 中引入的,所以从技术上讲,这对 OP 没有任何帮助,因为他们注意到 v2,但是对于像我一样偶然发现这个问题的未来人很有帮助
我花了一段时间来开发一些可以接受的答案并将其转变为强大功能的东西。
我不确定其他人,但我在使用 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 in one of his blog posts 概述的父范围。
我需要知道脚本名称及其执行位置。
当从主脚本和导入的 .PSM1 库文件的主行调用时,为 MyInvocation 结构添加前缀“$global:”会返回完整路径和脚本名称。它也可以在导入库中的函数内工作。
经过一番折腾,我决定使用 $global:MyInvocation.InvocationName。它可以与 CMD 启动、Run With Powershell 和 ISE 一起可靠地工作。本地和 UNC 启动都返回正确的路径。
ParameterArgumentValidationErrorNullNotAllowed
异常。
我总是使用同样适用于 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
使用所有这些答案和评论中的片段,我为将来看到这个问题的任何人整理了这个。它涵盖了其他答案中列出的所有情况,并且我添加了另一种我发现的故障保险。
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
}
我发现这里发布的旧解决方案不适用于 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"
如果任何其他方法失败,您也可以考虑 split-path -parent $psISE.CurrentFile.Fullpath
。特别是,如果您运行一个文件来加载一堆函数,然后在 ISE shell 中执行这些函数(或者如果您选择运行),则上面的 Get-Script-Directory
函数似乎不起作用。
$PSCommandPath
就可以在 ISE 中工作。否则,您实际上并没有执行脚本;您只是将命令“粘贴”到外壳中。
如果要从相对于脚本运行位置的路径(例如从“lib”子文件夹)加载模块,则需要使用以下方法之一:
$PSScriptRoot
在作为脚本调用时有效,例如通过 PowerShell 命令 $psISE.CurrentFile.FullPath
在您在 ISE 中运行时有效
但是,如果您不在其中,并且只是在 PowerShell shell 中输入,您可以使用:
pwd.Path
您可以根据运行的环境将这三个变量之一分配给名为 $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.
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
不定期副业成功案例分享
Split-Path
在这里有什么用?Split-Path
与-Parent
参数一起使用以返回当前目录,但不包含当前正在执行的脚本的名称。$PSScriptRoot
的更接近的 v2 近似是(Split-Path -Parent
应用于)$MyInvocation.MyCommand.Path
,而不是$MyInvocation.MyCommand.Definition
,尽管在脚本的顶级范围内它们的行为相同(即为此目的唯一明智的打电话的地方)。在函数或脚本块中调用时,前者返回空字符串,而后者返回函数体的/脚本块的定义作为字符串(一段 PowerShell 源代码)。-Parent
确实没有必要。