ChatGPT解决这个技术问题 Extra ChatGPT

PowerShell:从脚本目录运行命令

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

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

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


E
Eternal21

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

$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
B
Bill Tür stands with Ukraine

有很多投票的答案,但是当我阅读您的问题时,我以为您想知道脚本所在的目录,而不是脚本运行的目录。您可以使用 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


我一直在寻找的答案。其他人似乎比简单的问题解决了更多的问题。
J
Jaykul

如果您正在调用本机应用程序,则需要担心 [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 未自动设置的原因有两个注意事项:

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

如果要将其放入提示符中(仅在主运行空间中运行,单线程),则需要使用:

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

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

这会很好。

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir

不要忘记在最后调用 Pop-Location 以将路径返回到其原始状态。
D
Daniel Wu

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

$currentPath=Split-Path ((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path import-module "$currentPath\sqlps.ps1"


您想将 -Scope 设置为 Script
s
sashoalm

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

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

C
Community

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

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

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

添加另一个命令以运行以;分隔的脚本,其中是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"