我正在编写一个批处理文件,该文件执行一个 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 文件时才会发生这种情况?
我尝试过的事情
FileSystem::
和提供程序 http://powershell.org/wp/2014/02/20/powershell-gotcha-unc-paths-and-providers/-literalPath
参数代替普通 -path
参数来实现 Get-ChildItem
Get-ChildItem \\remote-server\foothing
并成功验证与远程服务器的连接我在运行引用 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 来查看您是否实际上是从非文件系统位置执行的。
Rory 的答案提供了一种有效的解决方法,但是有一个解决方案:不需要首先将当前位置更改为文件系统提供程序位置:
在 UNC 路径前添加 FileSystem::
$foo = @{
Name = "Foo"
Path = "FileSystem::\\remote-server\foothing"
}
$bar = @{
Name = "Bar"
Path = "FileSystem::\\remote-server\barthing"
}
调整,使用 Push-Location
和 Pop-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 当前位置关联的任何提供程序都将尝试处理它们。
添加前缀
FileSystem::
明确地将路径标识为
FileSystem
提供者路径,无论当前位置下的提供者是什么。请注意,这样的 provider 前缀只能被 PowerShell cmdlet 识别。
和
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,因为看起来正是这些东西改变了位置。