【问题标题】:PowerShell: Run command from script's directoryPowerShell:从脚本目录运行命令
【发布时间】:2011-06-11 02:11:27
【问题描述】:

我有一个 PowerShell 脚本,它使用脚本的当前目录执行一些操作。因此,在该目录中,运行 .\script.ps1 可以正常工作。

现在我想在不更改脚本的引用目录的情况下从不同的目录调用该脚本。所以我想调用..\..\dir\script.ps1 并且仍然希望该脚本的行为与从其目录中调用的一样。

我该怎么做,或者我如何修改脚本以便它可以从任何目录运行?

【问题讨论】:

    标签: powershell


    【解决方案1】:

    你的意思是你想要脚本自己的路径,这样你就可以引用脚本旁边的文件吗?试试这个:

    $scriptpath = $MyInvocation.MyCommand.Path
    $dir = Split-Path $scriptpath
    Write-host "My directory is $dir"
    

    您可以从 $MyInvocation 及其属性中获得大量信息。

    如果要引用当前工作目录中的文件,可以使用 Resolve-Path 或 Get-ChildItem:

    $filepath = Resolve-Path "somefile.txt"
    

    编辑(基于 OP 的评论):

    # temporarily change to the correct folder
    Push-Location $dir
    
    # do stuff, call ant, etc
    
    # now back to previous directory
    Pop-Location
    

    可能还有其他方法可以使用 Invoke-Command 实现类似的功能。

    【讨论】:

    • 嗯,好吧,也许我应该对我的脚本更清楚一点。实际上它是一个使用一些参数调用ant 的脚本。所以我必须从该文件夹中调用ant 以确保它正确找到配置文件。理想情况下,我正在寻找一些东西来临时更改该脚本中本地的执行目录。
    • 啊,那么在这种情况下,您将需要Push-LocationPop-Location
    • 请注意,$MyInvocation 是上下文相关的,我通常使用 $ScriptPath = (Get-Variable MyInvocation -Scope Script).Value.MyCommand.Path 来处理任何类型的嵌套或函数跨度>
    • As a oneliner - $MyInvocation.MyCommand.Path | Split-Path | Push-Location
    【解决方案2】:

    有很多投票的答案,但是当我阅读您的问题时,我以为您想知道脚本所在的目录,而不是脚本运行的目录。您可以通过 powershell 的自动变量获取信息

    $PSScriptRoot     # the directory where the script exists, not the
                      # target directory the script is running in
    $PSCommandPath    # the full path of the script
    

    例如,我有一个 $profile 脚本,它可以找到一个 Visual Studio 解决方案文件并启动它。一旦解决方案文件启动,我想存储完整路径。但我想保存原始脚本所在的文件。所以我使用了$PsScriptRoot

    【讨论】:

    • 我正在寻找的答案。其他的似乎比简单的问题解决了更多的问题。
    【解决方案3】:

    如果您正在调用本机应用程序,则需要担心 [Environment]::CurrentDirectory 而不是 PowerShell 的 $PWD 当前目录。由于各种原因,PowerShell 在您设置位置或推送位置时不会设置进程的当前工作目录,因此如果您正在运行期望设置它的应用程序(或 cmdlet),则需要确保这样做。

    在脚本中,您可以这样做:

    $CWD = [Environment]::CurrentDirectory
    
    Push-Location $MyInvocation.MyCommand.Path
    [Environment]::CurrentDirectory = $PWD
    ##  Your script code calling a native executable
    Pop-Location
    
    # Consider whether you really want to set it back:
    # What if another runspace has set it in-between calls?
    [Environment]::CurrentDirectory = $CWD
    

    没有万无一失的替代方案。我们中的许多人在我们的提示函数中添加了一行来设置 [Environment]::CurrentDirectory ...但是当您在脚本中更改位置时,这对您没有帮助。中。

    关于 PowerShell 不自动设置的原因的两个注意事项:

    1. PowerShell 可以是多线程的。您可以在单个进程中同时运行多个运行空间(请参阅 RunspacePool 和 PSThreadJob 模块)。每个运行空间都有自己的 $PWD 当前工作目录,但只有一个进程和一个环境。
    2. 即使您是单线程的,$PWD 也并不总是合法的 CurrentDirectory(例如,您可以 CD 到注册表提供程序)。

    如果你想把它放到你的提示符中(它只会在主运行空间中运行,单线程),你需要使用:

    [Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
    

    【讨论】:

    • 它不会因为路径提供程序而更改进程工作目录:您可能正在 CD 进入注册表、SQL 数据库或 IIS 配置单元等...
    • 是的。我知道,这就是最后一个“最后的说明”的重点。他们可以(就像我在提示函数中所做的那样)将其更新到文件系统提供程序的当前位置,就像世界上所有其他 shell 一样。
    • 神圣的脚本之神,我太失望了.\_/. — 这让我半天的时间都死了!人,认真的吗?认真吗?..
    • 现在基本不需要了,更现代的 PowerShell 版本在启动二进制应用程序时会设置工作目录。
    • 当原始[Environment]::CurrentDirectory$PWD 不同时,此方法无法恢复。正确的做法是将其存储到变量$origEnvDir = [Environment]::CurrentDirectory 中,然后再将其恢复为[Environment]::CurrentDirectory = $origEnvDir
    【解决方案4】:

    这样就可以了。

    Push-Location $PSScriptRoot
    
    Write-Host CurrentDirectory $CurDir
    

    【讨论】:

    • 不要忘记在最后调用Pop-Location 以将路径恢复到原始状态。
    【解决方案5】:

    我经常使用以下代码来导入与运行脚本位于同一目录下的模块。它将首先获取运行powershell的目录

    $currentPath=Split-Path ((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path

    导入模块“$currentPath\sqlps.ps1”

    【讨论】:

    • 你想将 -Scope 设置为 Script
    【解决方案6】:

    我用@JohnL 的解决方案做了一个单行:

    $MyInvocation.MyCommand.Path | Split-Path | Push-Location
    

    【讨论】:

      【解决方案7】:

      好吧,我一直在寻找解决方案,而没有任何仅来自 CLI 的脚本。我就是这样做的xD:

      • 导航到您要从中运行脚本的文件夹(重要的是您有选项卡完成)

        ..\..\dir

      • 现在用双引号将位置括起来,并在其中添加cd,这样我们就可以调用另一个powershell实例。

        "cd ..\..\dir"

      • 添加另一个命令以运行以;分隔的脚本,其中是powershell中的命令分隔符

        "cd ..\..\dir\; script.ps1"

      • 最后用另一个powershell实例运行它

        start powershell "cd..\..\dir\; script.ps1"

      这将打开新的 powershell 窗口,转到 ..\..\dir,运行 script.ps1 并关闭窗口。


      注意“;”只是分隔命令,就像您一个接一个地键入它们一样,如果第一个失败,第二个将运行,然后再运行,然后再运行...如果您想保持新的 powershell 窗口打开,您可以在传递的命令中添加 -noexit 。请注意,我首先导航到所需的文件夹,以便可以使用制表符完成(不能用双引号括起来)。

      start powershell "-noexit cd..\..\dir\; script.ps1"

      使用双引号 "",这样您就可以传递名称中带有空格的目录,例如,

      start powershell "-noexit cd '..\..\my dir'; script.ps1"

      【讨论】:

        猜你喜欢
        • 2021-09-13
        • 2017-12-07
        • 1970-01-01
        • 2013-08-29
        • 1970-01-01
        • 2012-11-23
        • 1970-01-01
        • 1970-01-01
        • 2020-08-12
        相关资源
        最近更新 更多