Запуск Get-ChildItem по пути UNC работает в Powershell, но не в Powershell, запущенном в пакетном файле
Я пишу командный файл, который выполняет Powershell script, который в одной точке перебирает элементы с путями UNC в качестве атрибутов и использует Get-ChildItem
на этих путях. В минимальной версии это то, что происходит в моих скриптах:
Master.bat
powershell -ExecutionPolicy ByPass -File "Slave.ps1"
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
}
Проблема, с которой я сталкиваюсь, заключается в том, что при запуске Master.bat он терпит неудачу при Get-ChildItem
с ошибкой в строках
get-childitem : Cannot find path '\\remote-server\foothing' because it does not exist.
Однако, кажется, он работает отлично, если я запускаю файл Slave.ps1 напрямую, используя Powershell. Почему это может происходить только при запуске файла Master.bat?
Вещи, которые я пробовал
- Предоставление UNC-путей с помощью
FileSystem::
с поставщиками http://powershell.org/wp/2014/02/20/powershell-gotcha-unc-paths-and-providers/
- Убедитесь, что в реальных путях нет странных символов.
- Используя параметр
-literalPath
вместо простого параметра -path
для Get-ChildItem
- Запуск
Get-ChildItem \\remote-server\foothing
в PowerShell и последующее подтверждение подключения к удаленному серверу
Ответы
Ответ 1
Я нашел эту проблему при запуске скриптов, ссылающихся на пути UNC, но ошибка возникает только тогда, когда корневой каталог script установлен в положение не файловой системы. например 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
}
Надеюсь, это поможет - я был бы очень доволен щедростью, так как это мой первый ответ на переполнение стека.
Постскриптум Я забыл добавить - root командной строки PS может быть задан автоматически загруженными модулями в конфигурации вашего устройства. Я бы посмотрел с помощью Get-Location, чтобы узнать, действительно ли вы выполняете его из местоположения без файловой системы.
Ответ 2
Ответ Rory обеспечивает эффективное обходное решение, но там решение, которое не требует изменения текущего местоположения в местоположении поставщика FileSystem, сначала
Префикс пути UNC с помощью FileSystem::
, чтобы убедиться, что они распознаны правильно, независимо от текущего местоположения:
$foo = @{Name = "Foo"}
$foo.Path = "FileSystem::\\remote-server\foothing"
$bar = @{Name = "Bar"}
$bar.Path = "FileSystem::\\remote-server\barthing"
Дополнительная справочная информация
Это отличное сообщение в блоге объясняет основную проблему (выделено мной):
PowerShell не распознает [UNC-пути] как "корневые", потому что они не находятся на PSDrive; как таковой любой поставщик, связанный с текущим местоположением PowerShell, попытается обработать их.
Добавление префикса FileSystem::
однозначно идентифицирует путь как путь поставщика FileSystem, независимо от поставщика, лежащего в основе текущего местоположения.
Ответ 3
Я где-то читал о Push-Location
и Pop-Location
, чтобы противостоять этой проблеме - я приземлился на ваш вопрос, пока вручную, шаг за шагом, тестировал новую процедуру, в которой script имеет push/pop, но я забыл сделать это в своем окне PS, После проверки ответа @Rory я заметил, что я был на PS SQLServer:\вместо PS C:\prompt.
Таким образом, способ использовать это на вашем "ведомом" script будет следующим:
$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
}
Мысль о добавлении Push/Pop до и после # Do things
, потому что кажется, что это те вещи, которые меняют местоположение.