PowerShell:从脚本的目录运行命令

pok*_*oke 134 powershell

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

现在我想从不同的目录调用该脚本而不更改脚本的引用目录.所以我想调用..\..\dir\script.ps1并仍然希望该脚本在其目录中调用时的行为.

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

Joh*_*hnL 185

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

$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"
Run Code Online (Sandbox Code Playgroud)

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

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

$filepath = Resolve-Path "somefile.txt"
Run Code Online (Sandbox Code Playgroud)

编辑(根据OP的评论):

# temporarily change to the correct folder
Push-Location $folder

# do stuff, call ant, etc

# now back to previous directory
Pop-Location
Run Code Online (Sandbox Code Playgroud)

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

  • 小心一点,$ MyInvocation是上下文敏感的,我通常做$ ScriptPath =(Get-Variable MyInvocation -Scope Script).Value.MyCommand.Path,它适用于任何类型的嵌套或函数 (5认同)
  • 那么在那种情况下你会想要'Push-Location`和`Pop-Location` (3认同)

Jay*_*kul 34

如果您正在调用本机应用程序,则需要担心[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
Run Code Online (Sandbox Code Playgroud)

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

最后注意事项:$PWD并不总是合法的CurrentDirectory(例如,您可能将CD放入注册表提供程序中),因此如果要将其放入提示或*-Location cmdlet的包装函数中,则需要使用:

[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
Run Code Online (Sandbox Code Playgroud)

  • 由于路径提供程序,它不会更改进程工作目录:您可能会将CD放入注册表,SQL数据库或IIS配置单元等... (3认同)
  • 神圣的脚本之神,我很失望`.\_/.` - 这让我浪费了半天时间!人,认真的?严重地?.. (2认同)
  • 现在几乎不需要了,更现代的PowerShell版本在启动二进制应用程序时会设置工作目录。 (2认同)

And*_*ndy 32

有大量投票的答案,但是当我读到你的问题时,我想你想知道脚本所在的目录,而不是脚本运行的位置.您可以使用powershell的自动变量获取信息

$PSScriptRoot - the directory where the script exists, not the target directory the script is running in
$PSCommandPath - the full path of the script
Run Code Online (Sandbox Code Playgroud)

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

  • 我一直在寻找的答案。其他问题似乎比直接问题解决了更多问题。 (2认同)

Dan*_* Wu 12

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

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

import-module"$ currentPath\sqlps.ps1"


小智 6

这样就可以了。

Push-Location $PSScriptRoot

Write-Host CurrentDirectory $CurDir
Run Code Online (Sandbox Code Playgroud)

  • 不要忘记在最后调用 `Pop-Location` 将路径返回到其原始状态。 (5认同)

sas*_*alm 5

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

$MyInvocation.MyCommand.Path | Split-Path | Push-Location
Run Code Online (Sandbox Code Playgroud)