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

ZEE*_*ZEE 5 powershell scripting path working-directory

当我从任何文件夹(例如)启动 PowerShell 脚本时C:\Scripts
脚本中的“当前”PowerShell 文件夹始终是用户配置文件文件夹
(例如c:\users\Joe;仅使用脚本进行测试Get-Location

但应该是启动脚本的文件夹......

我怎样才能解决这个问题?

mkl*_*nt0 10

当 PowerShell直接调用*.ps1脚本时,该脚本在进程内运行,与调用者位于同一运行空间中,因此默认情况下该脚本会看到与调用者相同的当前位置(工作目录) 。

顺便说一句:相反,如果脚本更改了当前位置,则调用者也会在脚本退出后看到这一点(有关详细信息,请参阅下文)。

如果您没有看到此行为,则意味着某些幕后代码正在更改当前位置。


我能真正看到这种情况发生的唯一方法是在以下场景中:

  • 如果(a)您的$PROFILE文件包含显式切换到您的主文件夹的Set-Location/命令,或者(b)(正如您的情况,正如我们现在所知)如果自动加载模块中有损坏的代码在(自动)导入[1]Push-Location

    • 您可以通过CLIpowershell.exe对于Windows PowerShellpwsh对于 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 
}
Run Code Online (Sandbox Code Playgroud)

答案的其余部分讨论了可能感兴趣的相关场景。


使用自己的目录作为工作目录(当前位置)执行 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
}
Run Code Online (Sandbox Code Playgroud)

笔记:

  • 显式恢复以前的位置(目录)的原因是PowerShell在进程中.ps1运行脚本(文件),因此如果脚本使用Set-LocationPush-Location更改当前位置,它将在会话全局范围内生效;也就是说,即使脚本退出后,新位置仍然存在。

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

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

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