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
您可以通过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)
通过 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 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-Location或Push-Location更改当前位置,它将在会话全局范围内生效;也就是说,即使脚本退出后,新位置仍然存在。
在类 Unix 平台(Linux、macOS)上,借助 PowerShell Core,您现在可以选择使用shebang行创建(无扩展名)可执行 shell 脚本;此类脚本在子进程中运行,因此无需恢复以前的位置(目录)。
$PSScriptRoot被破坏,如本 GitHub 问题中所述。[1] 任何模块都不应该在导入时更改会话全局状态(除了导入其命令之外),但这在技术上是可能的,即如果您将命令放置Set-Location在脚本模块文件的顶级范围*.psm1或通过ScriptsToProcess模块清单条目在调用者范围内运行的脚本。即使是二进制 cmdlet 也可以在导入时通过System.Management.Automation.IModuleAssemblyInitializer接口执行代码 - 请参阅此答案。