Batch file 在UNC路径上运行Get ChildItem可以在Powershell中工作,但不能在批处理文件中运行Powershell

Batch file 在UNC路径上运行Get ChildItem可以在Powershell中工作,但不能在批处理文件中运行Powershell,batch-file,powershell,cmd,unc,Batch File,Powershell,Cmd,Unc,我正在编写一个批处理文件,该文件执行一个Powershell脚本,该脚本在某一点上循环使用UNC路径作为属性的项,并在这些路径上使用Get ChildItem。在最低版本中,我的脚本中发生了以下情况: Master.bat powershell -ExecutionPolicy ByPass -File "Slave.ps1" 从.ps1 $foo = @{Name = "Foo"} $foo.Path = "\\remote-server\foothing" $bar = @{Name =

我正在编写一个批处理文件,该文件执行一个Powershell脚本,该脚本在某一点上循环使用UNC路径作为属性的项,并在这些路径上使用
Get ChildItem
。在最低版本中,我的脚本中发生了以下情况:

Master.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文件时才会发生这种情况

我尝试过的事情

  • 使用
    文件系统::
    和提供程序预先设置UNC路径
  • 确保实际路径中没有奇怪的字符
  • 使用
    -literalPath
    参数而不是
    Get ChildItem
    的普通
    -path
    参数
  • 在PowerShell中运行
    Get ChildItem\\remote server\foothing
    ,并成功验证与远程服务器的连接

我在运行引用UNC路径的脚本时发现了此问题,但只有当脚本的根目录设置为非文件系统位置时,才会发生此错误。e、 g.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提示符返回到文件系统位置。e、 g

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命令提示符root可能是由机器配置中的自动加载模块设置的。我会检查Get Location,看看您是否真的是从非文件系统位置执行的。

我在其他地方读到了关于解决这类问题的命令和命令-我在手动一步一步地测试一个新例程时遇到了您的问题,其中脚本有push/pop,但我忘了在我的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,因为似乎正是这些东西改变了位置。

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

在UNC路径前面加上
文件系统::
前缀,以确保正确识别这些路径,而不考虑当前位置:

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

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

或者,这里有一个调整Rory的答案避免全局更改当前位置会话(保留当前位置),使用
推送位置
弹出位置

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路径]识别为“根路径”,因为它们不在PSDrive上;因此,与PowerShell当前位置关联的任何提供程序都将尝试处理它们


添加前缀
文件系统::
明确地将路径标识为
文件系统
提供程序路径,而不考虑当前位置下的提供程序。

批处理文件是如何运行的?你只是双击它来运行它吗?它是否由任务计划程序运行?运行批处理文件时,是您的凭据在运行脚本吗?@TheMadTechnician以管理员身份运行脚本时,请右键单击.bat文件,然后单击“以管理员身份运行”以管理员身份运行脚本。当以管理员身份运行脚本时,是否提示输入凭据?如果只是以管理员身份运行批处理文件,而不是以管理员身份运行,是否会出现相同的错误?以管理员身份运行与不以管理员身份运行没有区别。无论如何都会出现错误。您正在运行哪个版本的PowerShell?我无法使用PowerShell v4或v3+1复制此问题,先生,您是个天才。我花了几个小时想弄明白为什么这对我不起作用!!非常感谢。谢谢,谢谢,谢谢!!我也有同样的问题,脚本失败了,将我踢回PS SQLSEVER\.+1非常好,我做cd$pwd以避免弄乱其他路径,但如果没有您的建议,这很难找到!7年后,你仍然在帮助我!!我已经挣扎了一段时间,你的解决方案对我非常有效。即使我在前面用[System.IO.Directory]::Exists($path)检查这行时,Get ChildItem-path$path Adding FileSystem::修复了它。很高兴听到这个消息,@kerzek。是的,使用
[System.IO.Directory]::Exists($path)
总是有效的,因为.NET只知道文件系统路径,而PowerShell有多个驱动器提供程序。使用
推送位置
/
弹出位置
临时切换到文件系统位置是一个好主意,但您的解决方案无法工作,因为(a)您的
Push-Location
命令位于
Get-ChildItem
之后,这是错误出现的地方,并且(b)即使您更改了顺序,
Push-Location
没有参数,也只是将当前位置推到记忆位置的堆栈上,它不会切换到文件系统位置,这正是此处需要的位置。