PowerShell: 从脚本目录运行命令

我有一个 PowerShell 脚本,它使用脚本的工作目录来做一些事情。因此,当在该目录中时,正确运行 .\script.ps1

现在我想从不同的目录调用这个脚本,而不需要更改脚本的引用目录。因此,我想调用 ..\..\dir\script.ps1,并且仍然希望该脚本按照从其目录中调用的方式运行。

我如何做到这一点,或者我如何修改脚本,以便它可以从任何目录运行?

282258 次浏览

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

$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 可能还有其他类似的方法。

如果你调用的是本地应用程序,你需要担心的是 [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 可以是多线程的。可以在一个进程中同时运行多个 Runspace (请参见 RunspacePool 和 PSThreadJob 模块)。每个 runspace 都有自己的工作目录,但只有一个进程和一个环境。
  2. 即使您是单线程的,$PWD也不总是合法的 CurrentDirectory (例如,您可以 CD 到注册表提供程序中)。

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

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

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

$currentPath = Split-Path ((获取变量 我的调用-范围 0)。值)。 MyCommand。路径

Import-module“ $currentPath sqlps.ps1”

答案有很多,但当我读到你的问题时,我以为你想知道脚本在哪里,而不是脚本在哪里运行。您可以通过 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脚本,它可以找到 VisualStudio 解决方案文件并启动它。我希望在解决方案文件启动后存储完整路径。但是我想保存原始脚本所在的文件。所以我用了 $PsScriptRoot

我一直在寻找这个解决方案一段时间,没有任何脚本只是从 CLI。我是这么做的 xD:

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

    ..\..\dir

  • 现在用双引号包围 location,并在其中添加 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"

Use double quotes "" so you could pass directories with spaces in names e.g.,

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

这样就行了。

Push-Location $PSScriptRoot


Write-Host CurrentDirectory $CurDir

我用@JohnL 的解决方案写了一句俏皮话:

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