Обходные пути

Обходные пути

Почему Invoke-Commandпри удаленном запуске команд результаты различаются, чем при локальном запуске тех же самых команд на той же самой системе?

Эти удаленно вызываемые команды отображают 4 пустые строки:

PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }

В то время как эти локальные команды выводят ожидаемые результаты:

PS > Invoke-Command cluster02 { cmd /c dir c:\ | select-string 'bytes free' }

11 Dir(s) 828,179,570,688 bytes free

Если я сначала запущу, Enter-PSSession cluster02а затем выполню их, обе команды вернут ожидаемый результат.

Это баг этого старого PowerShell (windows 2012) или я упускаю какую-то особенность PS? Если это баг или особенность, когда это проявляется? Другими словами, есть ли чему поучиться из этого странного поведения?

решение1

Проблема в том, что вы пытаетесь запустить удаленно команду cmd /ccmd dir, а затем удаленно передать ее команде PowerShell.

Хотя вы ожидаете, что при удаленном запуске все будет работать точно так же, как и локально, известно, что здесь есть различия, которые вызывают путаницу.

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

Проблема в том, что при подключении к удаленному компьютеру вы не разворачиваете полную пользовательскую среду. Технически вы не «входите» в машину в обычном смысле. Вы проходите аутентификацию, да, но примерно так же, как вы проходите аутентификацию в общей папке. У вашего удаленного подключения нет полного профиля пользователя, и поэтому все, что его ожидает, может получить ошибки и выйти из строя (даже если они не показывают этих ошибок).

К сожалению, простого решения этой проблемы нет.

Когда я работаю Invoke-Command -ScriptBlock {}с удаленной машиной, я стараюсь использовать команды PowerShell, насколько это возможно. Вам следует тщательно протестировать, если вы смешиваете cmd и PowerShell, поскольку это может работать не так, как при запуске во время интерактивного входа в систему.

Удаленный PowerShell, получить свободное место на диске в байтах (нет cmd)

Invoke-Command -ComputerName Cluster02 -ScriptBlock {(Get-PSDrive C).Free}

Выход

599257099776

Обходные пути

Установка выходных данных Invoke-Commandв качестве переменной, а затем выбор строки и свойства строки из нее, кажется, позволяет получить желаемый результат.

PowerShell (вариант 1)

$var = Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\" }; 
($var| select-string 'bytes free').Line.Trim();

Выход

11 Dir(s)  36,011,925,504 bytes free

Проблема, скорее всего,из-за вызова cmd /cи последующего выбора PowerShell-конвейером соответствующей строки из него в удаленном вызванном сеансе. Я обхожу эту проблему, сохраняя полный вывод из , invoke-commandкоторый возвращается правильно, как переменную вне invoke-command, а затем соответствующим образом анализирую эту переменную вне invoke-commandтакже.

PowerShell (вариант 2)

Вот то же самое, что и выше, но вместо того, чтобы добавлять переменную, просто передайте ее прямо Invoke-Commandв Select-Stringзапрос.

Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free';

Или даже что-то вроде этого...

(Invoke-Command cluster02 -ScriptBlock { cmd /c "dir c:\"; } | select-string 'bytes free').Line.Trim()

решение2

(пожалуйста, также проголосуйте за принятый ответ, если вам понравилась эта краткая версия)

TLDR-руководства

При удаленном запуске блоков скриптов:

  • Если возможно, избегайте запуска чего-либо, что не является собственным PowerShell. Например, замените cmd /c dir c:\|sls 'bytes free'на (Get-PSDrive C).Free.
  • Если нет, выполните наименьшее количество обработки в удаленной оболочке. Например, переместите select-string за пределы удаленной оболочки следующим образом: Invoke-Command cluster02 { cmd /c "dir c:\" } | sls 'bytes free'.

Связанный контент