Подтвердить что ты не робот

Запуск 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 и последующее подтверждение подключения к удаленному серверу
4b9b3361

Ответ 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, потому что кажется, что это те вещи, которые меняют местоположение.