PowerShell 脚本工作目录(当前位置)



当我从任何文件夹启动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-LocationPush-Location更改当前位置,它将全局会话生效;也就是说,即使在脚本退出后,新位置也会徘徊。

  • 类Unix平台(Linux,macOS(上,使用PowerShellCore,您现在可以选择使用shebang行创建(无扩展(可执行shell脚本;此类脚本子进程中运行,因此无需恢复之前的位置(目录(。

    • 不幸的是,从 PowerShell Core 7.0.0-preview.4 开始,访问有关脚本自身调用的信息(包括$PSScriptRoot(在基于 shebang 的脚本中被破坏,如本 GitHub 问题中所述。

[1] 任何模块都不应该在导入时更改会话全局状态(除了导入其命令(,但这在技术上是可行的,即如果您将诸如Set-Location之类的命令放在脚本模块*.psm1文件的顶级范围内,或者通过ScriptsToProcess模块清单条目在调用方的作用域中运行的脚本中。即使是二进制 cmdlet 也可以在导入时通过System.Management.Automation.IModuleAssemblyInitializer接口执行代码 - 请参阅此答案。

相关内容

  • 没有找到相关文章

最新更新