在 UNC 路径上运行 Get-ChildItem 在 Powershell 中有效,但在批处理文件中运行的 Powershell 中无效

问题描述 投票:0回答:3

我正在编写一个批处理文件,该文件执行一个 Powershell 脚本,该脚本在某一时刻循环使用 UNC 路径作为属性的项目,并在这些路径上使用

Get-ChildItem
。在最小版本中,这就是我的脚本中发生的情况:

大师.bat

powershell -ExecutionPolicy ByPass -File "Slave.ps1"

从机.ps1

$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"

$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"

@( $foo, $bar ) | ForEach-Object {
    $item = Get-ChildItem $_.Path
    # Do things with item
}

我遇到的问题是,当我运行 Master.bat 时,它在

Get-ChildItem
处失败,并出现类似

的错误
get-childitem : Cannot find path '\\remote-server\foothing' because it does not exist.

但是,如果我直接使用 Powershell 运行 Slave.ps1 文件,它似乎工作得很好。为什么只有在运行 Master.bat 文件时才会发生这种情况?

我尝试过的事情

batch-file powershell cmd unc
3个回答
48
投票

我在运行引用 UNC 路径的脚本时发现了此问题 - 但仅当脚本的根目录设置为非文件系统位置时才会发生该错误。例如PS SQLSEVER\

因此以下操作失败并出现相同的错误:

cd env:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"

$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"

@( $foo, $bar ) | ForEach-Object {
    $item = Get-ChildItem $_.Path
    # Do things with item
     Write-Host $item
}

所以我的解决方案是确保在执行此代码之前将 PS 提示符返回到文件系统位置。例如

cd env:
$foo = @{Name = "Foo"}
$foo.Path = "\\remote-server\foothing"

$bar = @{Name = "Bar"}
$bar.Path = "\\remote-server\barthing"

cd c: #THIS IS THE CRITICAL LINE
@( $foo, $bar ) | ForEach-Object {
    $item = Get-ChildItem $_.Path
    # Do things with item
     Write-Host $item
}

我希望这有帮助 - 我会对赏金感到非常满意,因为这是我关于堆栈溢出的第一个答案。 附:我忘记添加 - PS 命令提示符根可能是由您的计算机配置中自动加载的模块设置的。我会检查 Get-Location 来查看您是否实际上是从非文件系统位置执行的。


13
投票

Rory 的答案提供了一种有效的解决方法,但是有一个解决方案:不需要首先将当前位置更改为文件系统提供程序位置

在 UNC 路径前添加 FileSystem::

,以确保无论当前位置如何,都能正确识别它们:

$foo = @{ Name = "Foo" Path = "FileSystem::\\remote-server\foothing" } $bar = @{ Name = "Bar" Path = "FileSystem::\\remote-server\barthing" }


或者,这里是对 Rory 答案的

调整,使用 Push-LocationPop-Location

避免全局更改当前位置会话(以保留当前位置):
try {
  # Switch to the *filesystem provider's* current location, whatever it is.
  Push-Location (Get-Location -PSProvider FileSystem)

  # Process the paths.
  $foo, $bar | ForEach-Object {
      $item = Get-ChildItem $_.Path
      # Do things with item
  }
} finally {
   # Restore the previous location.
   Pop-Location
}

可选背景信息

这篇优秀的博客文章

解释了根本问题(强调):

PowerShell 无法将 [UNC 路径] 识别为“root”,因为它们不在 PSDrive 上;因此,
无论与 PowerShell 当前位置关联的任何提供程序都将尝试处理它们

添加前缀
FileSystem::

明确地将路径标识为

FileSystem
提供者路径,无论当前位置下的提供者是什么。
请注意,这样的 

provider 前缀只能被 PowerShell cmdlet 识别。


0
投票

Push-Location

Pop-Location
 命令来解决此类问题的内容 - 我在手动、逐步测试脚本已推送/的新例程时遇到了你的问题流行,但我忘了在我的 PS 窗口上做它们。检查@Rory的答案后,我注意到我在 PS SQLServer:\ 而不是 PS C:\ 提示符上。
因此,在“从属”脚本上使用它的方法是:

$foo = @{Name = "Foo"} $foo.Path = "\\remote-server\foothing" $bar = @{Name = "Bar"} $bar.Path = "\\remote-server\barthing" @( $foo, $bar ) | ForEach-Object { $item = Get-ChildItem $_.Path Push-Location # Do things with item Pop-Location }

考虑在
# Do things

之前和之后添加Push/Pop,因为看起来正是这些东西改变了位置。

    

© www.soinside.com 2019 - 2024. All rights reserved.