Почему область `using` работает локально с Start-Job, а не с Invoke-Command? - PullRequest
2 голосов
/ 31 января 2020

Почему PowerShell не позволяет использовать область using при локальном использовании Invoke-Command? Согласно документации , модификатор using может использоваться только для удаленных команд. Цитата:

Начиная с PowerShell 3.0, вы можете использовать модификатор области действия для определения локальной переменной в удаленной команде.

Такое поведение может быть продемонстрировано при запуске Invoke-Command локально:

$myServerName = 'www.google.com'
Invoke-Command { ping $using:myServerName }

При этом возникает следующая ошибка:

A Использование переменной не может быть получено. Переменная Using может использоваться только с Invoke-Command, Start-Job или InlineScript в рабочем процессе сценария. При использовании с Invoke-Command переменная Using действительна только в том случае, если на удаленном компьютере вызывается блок сценария.

Ошибка указывает, что удаленное использование модификатора using возможно только действителен удаленно, с Invoke-Command. Итак, если мы попробуем запустить ту же самую вещь, используя Start-Job, что произойдет?

$myServerName = 'www.google.com'
$j = Start-Job { ping $using:myServerName }
while( $j.State -eq 'Running' ){ Start-Sleep -s 1 }
Receive-Job $j

, которая не выдает ошибку, и я получаю ожидаемый результат:

 Pinging www.google.com [172.217.6.132] with 32 bytes of data:
 Reply from 172.217.6.132: bytes=32 time=20ms TTL=56
 Reply from 172.217.6.132: bytes=32 time=19ms TTL=56
 Reply from 172.217.6.132: bytes=32 time=19ms TTL=56
 Reply from 172.217.6.132: bytes=32 time=19ms TTL=56

Почему в документации говорится, что модификатор области действия using работает только удаленно, если его можно четко использовать и в локальном контексте? И точно так же, если он работает в контексте локального Start-Job, что мешает ему работать с локальным Invoke-Command?

Ответы [ 3 ]

2 голосов
/ 31 января 2020

Это верно при использовании «использования», потому что определение использования состояний

Начиная с PowerShell 3.0, вы можете использовать модификатор области применения для определения локальной переменной в удаленной команде

Каждый раз, когда вы используете $using, вы должны предоставить -ComputerName или -Session аргументы, независимо от того, является ли целевой сервер локальным или удаленным.

Например.

$myServerName = 'www.google.com'
Invoke-Command { ping $using:myServerName }
### BIG ERROR.

$myServerName = 'www.google.com'
Invoke-Command { ping $using:myServerName } -computername $env:COMPUTERNAME
### Ping response.

$myServerName = 'www.google.com'
Invoke-Command { ping $myServerName }
### Ping Reponse.

$using: поддерживается только в нескольких, определенных c контекстах, которые имеют одну общую черту: код, выполняемый вне текущего пространства выполнения - все остальные контексты не требуют и не поддерживают его. (@ mklement0)

[Invoke-Command, Start-Job и InlineScript - это известные контексты, которые поддерживают использование $using: для передачи переменных в текущем локальном сеансе.]

Документация о том, где вы можете использовать $using

1 голос
/ 01 февраля 2020

Примечание. Этот ответ не охватывает PowerShell рабочие процессы , поскольку они являются устаревшей технологией, более не поддерживаемой в PowerShell [Core] v6 + - см. этот блог post .

Для всего, что выполняется вне пространства выполнения, то есть не выполняется непосредственно в пространстве выполнения вызывающей стороны (поток), вам нужен $using: scope для встраивания переменной значения [1] из области действия вызывающего абонента , так что выход из пространства выполнения может получить к нему доступ. (И наоборот, все другие контексты не требуют и не поддерживают $using:)

Примечание. На момент написания этой статьи в связанной справке topi c отсутствуют важные аспекты того, что это Ответ резюмирует. Несколько ошибок GitHub были открыты, чтобы исправить это.

В частности, это включает следующие контексты:

  • Удаленно выполняемые команды , началось с Invoke-Command -ComputerName.

    • Runspace-local использование Invoke-Command - что и происходит без -ComputerName - не требует и не поддерживает ссылки $using: (он запускается в дочерней области области действия вызывающей стороны или, с -NoNewScope, непосредственно в области действия вызывающей стороны).

      • Использование локального пространства выполнения Invoke-Command редко требуется, поскольку оператор &, call (execute) (выполнение в дочерней области) и ., (точка-) оператор источника (выполнение непосредственно в области действия вызывающего), являются более лаконичными и эффективными альтернативами.
    • Обратите внимание, что если вы используйте параметр -ComputerName для целевого компьютера local , команда по-прежнему обрабатывается так, как если бы это было n, т. е. он проходит через инфраструктуру удаленного взаимодействия PowerShell, и применяются те же правила, что и для истинного удаленного выполнения.

  • Фоновые задания , запущено с Start-Job

  • Работы с нитями , запущенные с помощью Start-ThreadJob.

    • В PowerShell [Core] v7 + это также включает блоки сценариев, передаваемые в
      ForEach-Object с переключателем -Parallel.

Дистанционно выполняемые команды и фоновые задания запускаются вне процесса [2] , а для значений, пересекающих эти границы процесса, они под go XML сериализация и десериализация на основе , которая обычно включает потерю точности типа - как на входе, так и на выходе.

  • См. this Ответьте для справочной информации.

  • Обратите внимание, что это относится не только к значениям, встроенным в $using:, но и к значениям, передаваемым как argum вводит через параметр -ArgumentList (-Args) в Invoke-Command [-ComputerName] и Start-Job.

Задания потоков , напротив, потому что они запускать в другом пространстве выполнения (потоке) в том же процессе , получать $using: значения переменных в качестве своих исходных, живых объектов и, аналогично, возвращать такие объекты.

  • Предупреждение заключается в том, что может потребоваться явная синхронизация между пространствами выполнения (потоками) , если все они обращаются к данному изменяемому экземпляру ссылочного типа - который наиболее может произойти с ForEach-Object -Parallel.

  • Как правило, задания потоков в большинстве случаев являются лучшей альтернативой фоновым заданиям благодаря их значительно лучшей производительности, меньшему использованию ресурсов и точности типов.


[1] Обратите внимание, что это означает, что код внеполосного пространства никогда не может изменять переменные в области действия вызывающего . Однако в случае потоков заданий (но не во время удаленного взаимодействия и не в фоновых заданиях), если переменная значение оказывается экземпляром ссылочного типа (например (тип коллекции), можно изменить этот экземпляр в другом потоке, что требует синхронизации изменений между потоками, если несколько потоков выполнят изменения.

[ 2] В отличие от удаленных команд, фоновые задания выполняются на том же компьютере , но в (скрытом) PowerShell дочернем процессе .

0 голосов
/ 31 января 2020

Вам не нужно использование, если оно не удаленное:

invoke-command { ping $myservername } 

Обратите внимание, что вы должны быть администратором для вызова на локальном хосте.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...