当我从任何文件夹启动PowerShell脚本时(例如C:Scripts
(,
脚本中的"当前"PowerShell 文件夹 始终是用户配置文件文件夹
(例如c:usersJoe
;使用仅包含Get-Location
的脚本进行测试
(但应该是启动脚本的文件夹...
我该如何解决这个问题?
当 PowerShell直接调用*.ps1
脚本时,该脚本在进程中运行,与调用方位于同一运行空间中,因此默认情况下,脚本会看到与调用方相同的当前位置(工作目录(。
顺便说一句:相反,如果脚本更改了当前位置,则调用者也会在脚本退出后看到该位置(有关详细信息,请参见下文(。
如果未看到此行为,则意味着某些后台代码正在更改当前位置。
我能实际看到这种情况发生的唯一方法是在以下情况下:
-
如果 (a( 您的
$PROFILE
文件包含一个显式切换到您的主文件夹的Set-Location
/Push-Location
命令,或者(b((就像我们现在知道的那样(如果自动加载模块中有 - 损坏的 - 代码在(自动(导入时执行此操作[1]并且:-
您可以通过其CLI(
powershell.exe
用于Windows PowerShell,pwsh
用于PowerShell Core(调用PowerShell,而无需-NoProfile
开关;例如powershell -File someScript.ps1
-
在类 Unix 平台上,您的脚本被实现并调用为带有 shebang 行的无扩展、可执行的 shell 脚本(不包括
-NoProfile
- 有关详细信息,请参见下文(。
-
-
如果通过以下命令/功能之一运行脚本:
-
通过
Start-Job
(在子进程中(或Start-ThreadJob
(在新的运行空间中(,至少目前(PowerShell Core 7.0.0-preview.4(- 注意:这两个 cmdlet 的行为并不完全相同,这本身就有问题,但更大的问题是它们不会简单地继承调用方的当前位置 - 请参阅此 GitHub 问题。
-
通过 PowerShell SDK,在新的运行空间中。
-
除此之外,我只能看到意外的基于事件的代码产生您的症状,例如以下毫无意义的交互式提示字符串定义函数prompt
的重新定义,使其在每个命令后悄悄切换到$HOME
目录:
# !! Obviously, do NOT do this.
function prompt {
# Print the usual prompt string.
"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
# Quietly return to $HOME
Set-Location $HOME
}
答案的其余部分讨论了可能感兴趣的相关方案。
执行 PowerShell 脚本,其自己的目录作为工作目录(当前位置(:
在 PowerShell v3+ 中,自动变量$PSScriptRoot
包含执行脚本所在的目录的完整路径。
如果需要脚本使用自己的目录作为工作目录(当前位置(执行,请使用以下方法:
# Save the current location and switch to this script's directory.
# Note: This shouldn't fail; if it did, it would indicate a
# serious system-wide problem.
$prevPwd = $PWD; Set-Location -ErrorAction Stop -LiteralPath $PSScriptRoot
try {
# Your script's body here.
# ...
$PWD # output the current location
}
finally {
# Restore the previous location.
$prevPwd | Set-Location
}
注意:
显式还原以前位置(目录(的原因是PowerShell 在进程中运行脚本(
.ps1
文件(,因此,如果脚本使用Set-Location
或Push-Location
更改当前位置,它将全局会话生效;也就是说,即使在脚本退出后,新位置也会徘徊。在类Unix平台(Linux,macOS(上,使用PowerShellCore,您现在可以选择使用shebang行创建(无扩展(可执行shell脚本;此类脚本在子进程中运行,因此无需恢复之前的位置(目录(。
- 不幸的是,从 PowerShell Core 7.0.0-preview.4 开始,访问有关脚本自身调用的信息(包括
$PSScriptRoot
(在基于 shebang 的脚本中被破坏,如本 GitHub 问题中所述。
- 不幸的是,从 PowerShell Core 7.0.0-preview.4 开始,访问有关脚本自身调用的信息(包括
[1] 任何模块都不应该在导入时更改会话全局状态(除了导入其命令(,但这在技术上是可行的,即如果您将诸如Set-Location
之类的命令放在脚本模块*.psm1
文件的顶级范围内,或者通过ScriptsToProcess
模块清单条目在调用方的作用域中运行的脚本中。即使是二进制 cmdlet 也可以在导入时通过System.Management.Automation.IModuleAssemblyInitializer
接口执行代码 - 请参阅此答案。