Что касается , почему , быстрая цитата из этой статьи by meyer:
Преобразованный элемент создает содержащий блок даже для потомков которые были установлены в положение: исправлено. Другими словами, содержащий блок для потомка с фиксированной позицией преобразованного элемента является преобразованным элементом, а не видовым пространством
blockquote>. Это причудливое поведение, которое существует с 2011 года.
Как показано в вашем собственном ответе , PSv3 + использует специальную область $using:
, которая позволяет включать значения переменных из области вызывающей стороны . в блоки сценариев, выполненные удаленно - , решает вашу проблему . См. Нижний раздел, если вам нужно решить проблему в PowerShell v2.
Что касается , почему ваш оригинальный подход, основанный на -ArgumentList
, не работал :
В то время как блок скрипта, переданный Invoke-Command
, работает увидеть все, что было передано через -ArgumentList
в его непосредственном объеме, любых командах в нем, которые запускают через блок сценария ({ ... }
) - даже если они технически запустите в ту же область , как и в случае с Where-Object
и ForEach-Object
- , не не видят тот же массив $Args
, если он не равен ] явно передается - что не является опцией, когда блоки сценариев передаются в такие командлеты, как Where-Object
и ForEach-Object
.
Упрощенный пример (в котором даже не используется удаленное взаимодействие, что является следствием исходной проблемы):
Invoke-Command {
# OK - sees 'foo', because $Args reflects what was passed via -ArgumentList
"0: $($Args[0])"
# !! Does NOT see foo', because the script block executed by ForEach-Object
# !! - even though it runs in the same scope - has its own $Args definition
# !! and given that NO arguments were passed to *it*, the $Args that it
# !! sees is *empty* (an empty array).
'bar' | ForEach-Object { "1: $($Args[0])" }
} -ArgumentList 'foo'
Выше приведено:
0: foo
1:
, которое показывает, что Блок сценария, переданный в ForEach-Object
, больше не видит то же значение $Args
, что и область верхнего уровня блока сценария, переданного в Invoke-Command
.
Вы можете заставить свой оригинальный подход работать следующим образом (что необходимо, если вы застряли в PowerShell v2):
Invoke-Command {
# OK - sees 'foo', because $Args reflects what was passed via -ArgumentList
"0: $($Args[0])"
# Save the original $Args array...
$ArgsSaved = $Args
# ... and reference the *saved* array in the script block.
'bar' | ForEach-Object { "1: $($ArgsSaved[0])" }
} -ArgumentList 'foo'