
Почему 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 /c
cmd 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'
.