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

Jon*_*han 22 powershell cmd unc batch-file

我正在编写一个执行Powershell脚本的批处理文件,该脚本在某一时刻将具有UNC路径的项作为属性循环并Get-ChildItem在这些路径上使用.在最小版本中,这是我的脚本中发生的事情:

Master.bat

powershell -ExecutionPolicy ByPass -File "Slave.ps1"
Run Code Online (Sandbox Code Playgroud)

Slave.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
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是,当我运行Master.bat时,它会因为Get-ChildItem错误而失败

get-childitem : Cannot find path '\\remote-server\foothing' because it does not exist.
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用Powershell直接运行Slave.ps1文件,它似乎完全正常.为什么只有在运行Master.bat文件时才会发生这种情况?

我尝试过的事情

Ror*_*ory 40

我在运行引用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
}
Run Code Online (Sandbox Code Playgroud)

所以我的决心是确保在执行此代码之前将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
}
Run Code Online (Sandbox Code Playgroud)

我希望这会有所帮助 - 我会对赏金感到非常满意,因为这是我对堆栈溢出的第一个答案.PS我忘了添加 - PS命令​​提示符root可以由机器配置中的自动加载模块设置.我会检查Get-Location,看看你是否真的从非FileSystem位置执行.

  • +1先生,你是个天才.我花了几个小时试图弄清楚为什么这对我不起作用!! 非常感谢. (2认同)
  • 谢谢你,谢谢你,谢谢你!!我有相同的问题脚本失败并踢回PS SQLSEVER \. (2认同)
  • +1非常好,我做CD $ pwd不会弄乱其他路径,但是如果没有你的建议,这很难找到! (2认同)

mkl*_*nt0 12

Rory的回答提供了一种有效的解决方法,但是有一种解决方案不需要首先将当前位置更改为FileSystem提供者位置:

使用UNC路径前缀FileSystem::以确保它们被正确识别,而不管当前位置如何:

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

$bar = @{Name = "Bar"}
$bar.Path = "FileSystem::\\remote-server\barthing"
Run Code Online (Sandbox Code Playgroud)

或者,这里是对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
}
Run Code Online (Sandbox Code Playgroud)

可选的背景信息

这篇优秀的博客文章解释了潜在的问题(强调增加):

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

添加前缀FileSystem::明确地将路径标识为FileSystem提供者路径,而不考虑当前位置下的提供者.