【问题标题】:PowerShell script working directory (current location)PowerShell 脚本工作目录(当前位置)
【发布时间】:2020-02-06 08:31:27
【问题描述】:

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

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

我该如何解决这个问题?

【问题讨论】:

    标签: powershell path scripting working-directory


    【解决方案1】:

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

    顺便说一句:相反,如果脚本更改当前位置,调用者也会在脚本退出后看到这一点(详见下文)。

    如果您没有看到此行为,则暗示某些幕后代码正在改变当前位置。


    我可以真实地看到这种情况发生的唯一方法是在以下情况下:

    • 如果 (a) 您的 $PROFILE 文件包含明确切换到您的主文件夹的 Set-Location / Push-Location 命令 (b)(如您的情况,我们现在知道) 如果在自动加载模块中存在(自动)导入[1]的自动加载模块中的代码:

      • 您通过其CLI 调用 PowerShell(powershell.exe 用于 Windows PowerShellpwsh 用于 PowerShell Core没有 @987654332 @开关;例如powershell -File someScript.ps1

      • 在类 Unix 平台上,您的脚本被实现并调用为带有 shebang 行的无扩展、可执行的 shell 脚本(不包括 -NoProfile - 详情见下文)。

    • 如果您通过以下命令/功能之一运行脚本:

      • 通过Start-Job(在子进程中)或Start-ThreadJob(在新的运行空间中),至少目前是(PowerShell Core 7.0.0-preview.4)

        • 注意:这两个 cmdlet 的行为并不完全相同,这本身就有问题,但更大的问题是它们不简单地继承 调用者的当前位置 - 请参阅 @ 987654322@.
      • 通过 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改变当前位置,它生效session-globally;也就是说,即使在脚本退出后,新位置仍然存在。

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 2012-04-11
      • 2016-04-30
      • 2011-07-12
      相关资源
      最近更新 更多