在使用Expand-Archive命令时,如何在PowerShell中获得类似于%~dp0的等效路径?

5

我对脚本编写(尤其是PowerShell)和Stack Overflow都很新,因此请原谅我的无知并请耐心等待!我将尽力明确地解释我想要做的事情,并希望有人能详细回答我该做什么来使其有效。

预期的处理/工作流程:一个同事下载了包含所有必要文件的“Install.zip”文件。这个“Install.zip”文件包含“Setup.bat”文件(用于计算机配置), “Fubar.zip”文件,2个powershell脚本和一个自定义powerplan(.pow)文件。一旦下载完成,他们将运行“Setup.bat”文件,它将几乎完成所有工作。在批处理文件内部,它调用2个powershell脚本。1)“Download.ps1”-从Web下载其他文件。 2)“Unzip.ps1” -解压“Fubar.zip”并将内容放入另一个文件夹-C:\ TEST \

问题:我最近熟悉了在批处理文件中使用%〜dp0。我希望确保同事最初下载Install.zip的位置不会影响我的批处理文件。例如..有些人会将.zip文件下载到“Downloads”文件夹,然后将内容提取到正确的目标位置。其他人将在特定文件夹中下载.zip,然后在那个文件夹中解压它。[例如:C:\ Alex \ Install.zip--提取-- C:\ Alex \ Install \((内容))]因此,由于变量,我尝试不预定义文件位置。我已经让%〜dp0在批处理文件中的所有需要使用它的地方正常工作。我的唯一问题是如何使powershell脚本使用与批处理文件相同的工作目录。 *我的批处理文件和powershell脚本将始终位于相同的目录中。(无论路径是什么)

目标:我希望我的powershell脚本(“Unzip.ps1”)在其当前运行的目录中查找“Fubar.zip”文件。 (再次-无论路径是什么)。我基本上想消除可能影响powershell脚本的任何变量。我希望它始终使用其当前工作目录来定位Fubar.zip。我基本上需要powershell使用其当前工作目录或找到一种方法来获取其当前工作目录并使用该目录查找“Fubar.zip”。

我当前的“Unzip.ps1” powershell脚本非常基本。

Unzip.ps1:Expand-Archive -Force c:\ ALEX \ Install.zip \ Fubar.zip -dest c:\ TEST \

调用Unzip.ps1脚本的批处理文件命令:Powershell.exe -executionpolicy remotesigned -File %〜dp0UNZIP.ps1

请记住,我正在学习脚本编写,并且正在自学。我的知识有限,但我已经走到了这一步,这是我卡住的唯一部分。请给出清晰的响应。任何帮助或建议将非常感激!使用PowerShell 5.0

提前感谢您!


Split-Path -Parent $MyInvocation.MyCommand.Path 或者 Split-Path -Parent $PSCommandPath 或其他什么? - JosefZ
3个回答

7
cmd.exe%dp0在PowerShell v3+中的等效项是$PSScriptRoot
这两种构造都扩展为手头的批处理文件/PowerShell脚本所在文件夹的绝对路径。 (唯一的区别是%dp0包含一个尾随的\,而$PSScriptRoot则不包含)。
因此,要使您的Unzip.ps1脚本引用与脚本本身位于同一文件夹中的Fubar.zip,请使用:
Expand-Archive -Force $PSScriptRoot\Fubar.zip -dest c:\TEST\
  • 将路径构建为$PSScriptRoot\Fubar.zip - 即,简单地使用\连接变量值和文件名 - 是一个实用的快捷方式。更恰当的表达应该是(Join-Path $PSScriptRoot Fubar.zip)。在此情况下使用它是安全的,但请参见注释以了解何时应该使用Join-Path

  • 自动变量$PSScriptRoot需要PS v3+; 在v2-中,请使用
    Expand-Archive -Force ((Split-Path $MyInvocation.Mycommand.Path) + '\Fubar.zip') -dest c:\TEST\


Join-Path 会为您处理反斜杠\ - Mathias R. Jessen
@MathiasR.Jessen:谢谢 - Join-Path 绝对是值得了解的,但在这种情况下有些过度(路径分隔符是固定的,而且没有通配符需要解析)。 - mklement0
使用 Join-Path 并不是过度设计。如果脚本位于 C: 的根目录中,则 $PSScriptRoot 将为 C:\,带有尾部反斜杠。如果脚本位于名为 test 的子文件夹中,则 $PSScriptRoot 将为 C:\test,没有尾部反斜杠。使用 Join-Path 是处理这种情况最简单的方法。 - Bacon Bits
@BaconBits:是的,Join-Path 可以正确处理根路径,这在路径被 显示 在某个地方时更可取,但在 功能上 它在这里没有任何区别(尝试 Get-Item C:\\Windows),所以在 这种 情况下 - 不是一般情况,也不总是 - 我投票支持简单。 - mklement0

4
根据您的描述,我了解到和在同一个目录中。我们假定这个目录是,尽管我知道可能会改变。
如果从CMD启动,则PowerShell的工作目录将为您所在的目录;否则,它将来自<$env:UserProfile>。由于<.bat>文件总是从与其相同的目录()调用,因此powershell.exe将使用此命令找到它(您仍然可以在此处使用<%~dp0>;它没有任何问题)。
powershell.exe -ExecutionPolicy RemoteSigned -File Unzip.ps1

Unzip.ps1中,您将使用Get-Location:
Expand-Archive -Force "$(Get-Location)\Fubar.zip" -dest c:\TEST\

然而,如果.bat文件进入另一个目录,这将不起作用。从您的%~dp0UNZIP.ps1示例中,我假设这不是这种情况,但我们仍需解决它。如果是这种情况,您需要从脚本所在位置处理。因此,在此调用时,请提供.ps1的完整/相对路径:

powershell.exe -ExecutionPolicy RemoteSigned -File C:\Users\Me\Temp\Unzip.ps1

那么,您的Unzip.ps1需要像这样:

Expand-Archive -Force "${PSScriptRoot}\Fubar.zip" -dest 'C:\TEST\'

或者,您也可以像@JosefZ建议的那样进行一些花式路径拆分。 $PSCommandPath$MyInvocation变量包含您的脚本的完整路径; 您应该熟悉它们:

$location = Split-Path $PSCommandPath -Parent
$location = Split-Path $MyInvocation.MyCommand.Path -Parent
Expand-Archive -Force "${location}\Fubar.zip" -dest 'C:\TEST\'
< p > < strong > < em > 注意: < em >当然,您不会两次设置< code > $location 。我只是向您展示了两种设置方法。

我希望这可以帮助您!


有一些好的信息,但是批处理文件并没有改变当前目录:它从当前目录调用powershell.exe,并使用PowerShell脚本的绝对路径。 除此之外:虽然向初学者介绍Get-Location可能会有帮助,但在这里使用它是不必要的。 - mklement0
1
值得一提的是,$PSScriptRoot$PSCommandPath 是v3 +并且在那里更受欢迎; 在v2-上, $MyInvocation.MyCommand.Path$MyInvocation.InvocationName更好,因为后者(a)只包含 . 如果脚本正在以点源方式加载,否则包含调用路径_如指定_,这不一定是完整路径。 - mklement0
1
这太完美了!感谢你们的专业知识和耐心!非常感激! - SrPhaux
@mklement0 这只是教学点,伙计。你说得对,$MyInvocation.MyCommand.Path更好...我写这篇文章时已经很晚了。;)我们可以整天争论“如果”问题,但我只是试图给他提供很多选项,因为我没有所有的源文件。此外,他为什么要调用多个.ps1文件?为什么要从.bat中调用.ps1;直接从.ps1开始不就行了吗?我可以提出很多问题,但都超出了OP的范围。 - VertigoRay
我认为你想教别人是很好的,这显然也是 OP 想要的。感谢你更新到 $MyInvocation.MyCommand.Path。 我的其他评论并不是关于“如果”的问题;它们指出了一个错误的前提(批处理文件会更改当前目录),并建议在输入路径到 Export-Archive 时使用 Get-Location 可能会分散注意力(因为这可能会让新手认为这是必需的或良好的实践,这是我在之前的评论中没有明确说明的事情)。 - mklement0
关于教学的另一个想法:当提供多种实现方式时,为初学者提供何时选择哪种方法的指导是有帮助的;因此,我建议推荐使用$PSCommandPath(如果可用),并提及v3+的要求。再想一想:$PSScriptRoot(同样也需要v3+)直接提供了脚本文件夹的路径。 - mklement0

0

在 Powershell 3 之前

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

否则,$PsScriptRoot将起作用。但是,如果你要依赖它,我建议你在脚本中标记#Requires -version 3
我建议不要改变PWD,除非你必须这样做。也就是说,直接引用变量即可。

好的提示,但是为什么您认为应该使用(Get-Variable MyInvocation -Scope 0).Value而不是简单的$MyInvocation - mklement0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接