Назад | Перейти на главную страницу

Используйте Powershell для запуска программы с графическим интерфейсом на удаленном компьютере

В одной сети установлены две машины с Windows 7.
Я включил все необходимое, чтобы они могли общаться с winrm.

Когда я запускаю следующую команду:

Invoke-Command -ComputerName REMOTE-PC -ScriptBlock { Start-Process calc.exe }

Он работает правильно, но программа никогда не отображается на удаленном компьютере. Насколько я могу судить, это ожидаемое поведение.

Я предполагаю, что процесс запускается правильно, а затем сразу же закрывается по окончании сеанса. Как мне запустить программу, чтобы она появилась на хост-машине?

По замыслу, вы не должны запускать процессы в сессиях других людей.

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

Это просто противоречит модели безопасности самой Windows, и попытки подорвать ее будут осуждены. Так что вы вряд ли найдете простой и приемлемый способ сделать это. Это технически возможно, но это включает запуск в качестве локальной системы, копирование токена безопасности другого зарегистрированного пользователя и запуск процесса с этим альтернативным токеном. Для этого вам понадобится Windows API, и это почти единственное, в чем Powershell не очень хорош. Видеть WTSQueryUserToken и CreateProcessAsUser в Windows API для более подробной информации.

Еще одна идея, чтобы полностью не мочиться в Cheerios, вы могли бы выполнить это, удаленно создав запланированное задание, которое запускает процесс. Видеть https://devblogs.microsoft.com/scripting/how-can-i-remotely-start-an-interactive-process/ для получения дополнительной информации об этом.

Редактировать: О, и я забыл ... почти наверняка PsExec с -i параметр может это сделать. Вы должны указать идентификатор сеанса входа в систему. И иметь на это разрешение. Скорее всего, он использует тот же Windows API, о котором я упоминал, который использует тот факт, что PsExec устанавливает временную службу, которая работает как локальная система.

Я смог заставить это работать с помощью PsExec, как упоминалось в другом ответе.

  1. Скачать PSTools
  2. Распаковать в C:\Windows\PSTools
  3. Добавить C:\Windows\PSTools на ваш ПУТЬ
  4. Получить идентификатор процесса сеанса RDP (tasklist будет работать, или причудливый однострочный: $session = tasklist /fo CSV | findstr RDP ; $session = $session.Split(",")[3] ; $session.Split('"')[1])
  5. Процесс запуска: PsExec.exe -s -i 123 calc.exe («123» - это идентификатор сеанса RDP)

Вот как я делаю это с Ansible 2.3.0:

- name: get RDP session number
  win_shell: "{{ item }}"
  with_items:
    - $session = tasklist /fo CSV | findstr RDP ; $session = $session.Split(",")[3] ; $session.Split('"')[1]
  register: rdp_session

- name: start calc.exe
  win_shell: PsExec.exe -s -i {{ rdp_session.results[0].stdout_lines[0] }} calc.exe

Вы можете создать «вызываемую ловушку» на удаленном компьютере: это запланированная задача, настроенная на «запускать только при входе пользователя в систему», назначенная для запуска под учетной записью пользователя, который будет входить в систему после выполнения. Действие задачи - это исполняемый файл, который вы хотите запустить.

Запланированные задачи могут быть созданы удаленно с помощью powershell или schtasks, а затем вызываться просто по «имени» самой задачи с помощью schtasks или Start-ScheduledTask в PowerShell.

  1. На удаленном компьютере создайте запланированную задачу barebones, которая запускается пользователем, выполняющим текущий сеанс.
  2. Установите задачу на запуск "только когда пользователь вошел в систему"
  3. Если .exe или элемент на вкладке «Действие» запланированной задачи имеет параметр «Запуск от имени администратора» для элемента файловой системы (щелкните правой кнопкой мыши, «Свойства», «Совместимость> Запуск от имени администратора»), запланированную задачу необходимо запустить с повышенными привилегиями. привилегии, иначе он выйдет из строя или не появится.
  4. Автор запланированной задачи должен иметь права администратора, чтобы при ее удаленном вызове вы могли использовать эту учетную запись администратора для вызова запланированной задачи, которая затем запускается в профиле пользователя, указанном в разделе «Запускать только при входе пользователя в систему».
  5. Убедитесь, что машина вошла в систему как этот пользователь.
  6. Это может зависеть от приложения, если эта задача будет выполняться должным образом, если машина заблокирована. По моему опыту, да.
  7. Отсюда вы можете использовать schtasks.exe и вызвать имя запланированной задачи вместе с именем хоста и передать учетные данные повышенной учетной записи, используемой для создания запланированной задачи (а не пользователя, который будет входить в систему).
  8. Вы также можете вызвать его в PowerShell, если на удаленном компьютере работает версия PowerShell, поддерживающая Start-ScheduledTask.

Чтобы вызвать задачу, вы ссылаетесь на задачу по имени, которое вы ей дали:

schtasks /run /TN "mytaskname" /s "host" /u "user" /p "password"

Удаленное создание запланированной задачи возможно с помощью schtasks.exe или New-ScheduledTaskPrincipal в PowerShell. Если исполняемый файл или элемент «Действие» в задаче помечен как «запускать от имени администратора» в файловой системе, задача потребует присоединения учетных данных New-ScheduledTaskPrincipal во время создания задачи, чтобы установить это свойство соответствующим образом.

Пользователь, вошедший в систему в данный момент, может быть движущейся целью, хотя его можно запросить с помощью Get-LoggedOnUser через PowerShell до самого создания запланированной задачи.

Подробный код для этого появится в ближайшие 48 часов, я хотел сделать базовую структуру доступной для всех вас.

Если вы хотите избежать RDPing для получения идентификатора процесса в ответе Виктора, вы можете сделать это, вызвав query session команда на удаленном компьютере. Пример сценария Powershell

$user = "some_user"
$password = "password of the user"
$ComputerName = "name of the remote machine"

$processId = Invoke-Command $session -ScriptBlock  {
param($user)
    $sessions = query session $user;
    return $sessions[1].split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)[2];

} -ArgumentList ($user)

PsExec \\$ComputerName -u $user -p $password -h -i $processId [some executable name]  [arguments to be passed if any]