每当我需要引用一个公共模块或脚本时,我喜欢使用相对于当前脚本文件的路径,这样,我的脚本总能找到库中的其他脚本。
那么,确定当前脚本目录的最佳标准方法是什么?目前,我正在做:
$MyDir = [System.IO.Path]::GetDirectoryName($myInvocation.MyCommand.Definition)
我知道在模块(.psm1)中你可以使用$PSScriptRoot
来获取这些信息,但这不会在常规脚本(即.ps1文件)中设置。
获取当前PowerShell脚本文件位置的规范方法是什么?
答案 0 :(得分:737)
# 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
答案 1 :(得分:57)
如果要创建V2模块,可以使用名为的自动变量
$PSScriptRoot
。
来自PS>帮助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.
答案 2 :(得分:29)
适用于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
}
答案 3 :(得分:14)
也许我在这里遗漏了一些东西......但是如果你想要当前的工作目录,你可以使用它:(Get-Location).Path
表示字符串,或Get-Location
表示对象。
除非你指的是这样的东西,我在再次阅读这个问题后理解这一点。
function Get-Script-Directory
{
$scriptInvocation = (Get-Variable MyInvocation -Scope 1).Value
return Split-Path $scriptInvocation.MyCommand.Path
}
答案 4 :(得分:11)
与已发布的答案非常相似,但管道看起来更像PS。
$PSCommandPath | Split-Path -Parent
答案 5 :(得分:11)
For Powershell 3 +
Private Function GetData() As Object
Dim sql As String = "Select Data from Table where Option = ?"
Return FunctionObject(sql, New List(Of Object) From {"This is a Test"})
End Sub
Public Function FunctionObject(ByVal sql As String, ByVal parameters As List(Of Object)) As Object
Using sqlconnection As New SQLiteConnection(ConnectionString)
sqlconnection.Open()
Using Cmd As New SQLiteCommand(sql, sqlconnection)
Dim par As SQLiteParameter
For Each parm As Object In parameters
par = Cmd.CreateParameter()
par.Value = parm
Cmd.Parameters.Add(par)
Next
FunctionObject = Cmd.ExecuteScalar()
End Using
End Using
End Function
我已将此功能放入我的个人资料中。也可以使用F8 / Run Selection在ISE中工作。
答案 6 :(得分:10)
我使用automatic variable $ ExecutionContext,它适用于PowerShell 2及更高版本。
$ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath('.\')
$的ExecutionContext 包含表示的EngineIntrinsics对象 Windows PowerShell主机的执行上下文。您可以 使用此变量来查找执行对象 可用于cmdlet。
答案 7 :(得分:7)
我需要知道脚本名称及其执行位置。
从MyInvocation结构前缀“$ global:”会在从主脚本和导入的.PSM1库文件的主线调用时返回完整路径和脚本名称。它也可以在导入库中的函数内工作。
经过多次摆弄后,我决定使用$ global:MyInvocation.InvocationName。 它可靠地运行CMD,Run With Powershell和ISE。 本地和UNC启动都会返回正确的路径。
答案 8 :(得分:7)
花了一些时间来开发一些能够接受已接受答案并将其变成强大功能的东西。
不确定其他人,但我在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在blog
中概述的父母范围。答案 9 :(得分:3)
我总是以相同的方式使用适用于Powershell和ISE的小片段代码:
function doGet(e){
if(typeof e.parameter.code !== 'undefined') {
var code = e.parameter.code;
getAccessToken(code);
}
return ContentService.createTextOutput('someThink..');
}
function getAccessToken(code){
var API_TOKEN_URL = 'https://discordapp.com/api/oauth2/token'
var CLIENT_ID = 'XYZ'
var CLIENT_SECRET = 'XYZ'
var REDIRECT_URI = 'https://script.google.com/macros/s/AKfycbyyt9-FiVv0zXOr8p8pMfojwEs2AXvBftVN1xdWeU3UQ1xgURD/exec'
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI,
'scope': 'identify'
}
header = {
'method' : 'post',
'Content-Type': 'application/x-www-form-urlencoded',
'payload' : data
}
var result = UrlFetchApp.fetch(API_TOKEN_URL, header);
if (result.getResponseCode() == 200) {
var params = JSON.parse(result.getContentText());
Logger.log(params.access_token); // all is fine
getUser(params.access_token, params.token_type)
}
}
答案 10 :(得分:2)
如果任何其他方法失败,您也可以考虑split-path -parent $psISE.CurrentFile.Fullpath
。特别是,如果你运行一个文件来加载一堆函数然后在ISE shell中执行这些函数(或者如果你运行选择),那么上面的Get-Script-Directory
函数似乎不起作用。
答案 11 :(得分:1)
发现此处发布的较旧的解决方案不适用于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"
HTH
答案 12 :(得分:0)
利用所有这些答案和评论中的内容,我将其汇总给以后遇到此问题的任何人。它涵盖了其他答案中列出的所有情况
# If using ISE
if ($psISE)
{
$ScriptPath = Split-Path -Parent $psISE.CurrentFile.FullPath
}
# If Using PowerShell 3 or greater
elseif($PSVersionTable.PSVersion.Major -gt 3)
{
$ScriptPath = $PSScriptRoot
}
# If using PowerShell 2 or lower
else
{
$ScriptPath = split-path -parent $MyInvocation.MyCommand.Path
}
答案 13 :(得分:0)
如果要从相对于脚本运行路径的路径(例如从“ 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.
答案 14 :(得分:-3)
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