PowerShell:从脚本目录运行命令


144

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

现在,我想从其他目录中调用该脚本,而无需更改脚本的引用目录。因此,我想调用..\..\dir\script.ps1并且仍然希望该脚本的行为与从其目录内部被调用时的行为相同。

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

Answers:


200

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

$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 $folder

# do stuff, call ant, etc

# now back to previous directory
Pop-Location

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


1
嗯,好的,也许我应该对我的脚本更加清楚了。实际上,它是一个ant使用一些参数调用的脚本。因此,我必须ant从该文件夹中调用以确保它正确找到了配置文件。理想情况下,我正在寻找可以在该脚本中临时更改执行目录的内容。

3
阿然后在这种情况下,你会想Push-LocationPop-Location
JohnL

5
请注意,$ MyInvocation是上下文敏感的,我通常会执行$ ScriptPath =(Get-Variable MyInvocation -Scope Script).Value.MyCommand.Path,它可以从任何嵌套或函数中进行工作
Ion Todirel 2013年

39

如果要调用本机应用程序,则无需担心[Environment]::CurrentDirectoryPowerShell的$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

没有万无一失的选择。我们很多人把线在我们的提示功能设定[环境] :: currentDirectory所...但是,这并不能帮助你,当你改变位置的脚本。

关于PowerShell无法自动设置的原因的两点说明:

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

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

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

4
由于路径提供者,它不会更改进程的工作目录:您可能正在CD'ing到注册表,SQL数据库或IIS配置单元等中……
piers7 2013年

1
是。我知道,这就是最后一个“最后注”的要点。他们可以(就像我在提示函数中所做的那样)将其更新到FileSystem提供程序的当前位置,就像世界上其他所有shell一样。
Jaykul

2
神圣的脚本之神,我实在感到灰心丧气.\_/.-因为我半天丧命!人,认真吗?认真吗?..
ulidtko 2014年

2
现在几乎没有必要了,更现代的PowerShell版本在启动二进制应用程序时会设置工作目录。
Jaykul

1
这种方法在恢复原始失败[Environment]::CurrentDirectory时不同于$PWD。正确的做法是将其存储到变量中$origEnvDir = [Environment]::CurrentDirectory,然后再将其还原[Environment]::CurrentDirectory = $origEnvDir
斯特罗姆

37

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


12

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

$ currentPath =分割路径((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path

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


您想要将-Scope设置为Script
Ion Todirel,2013年

9

这样就可以了。

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir

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

2

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

  • 导航到要从中运行脚本的文件夹(重要的是您具有制表符补全)

    ..\..\dir

  • 现在将位置用双引号引起来,并在其中加上add 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"


0

我用@JohnL的解决方案制作了一个单行代码:

$MyInvocation.MyCommand.Path | Split-Path | Push-Location
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.