web-dev-qa-db-fra.com

Utiliser Powershell pour démarrer un programme GUI sur une machine distante

Il existe deux machines Windows 7 configurées sur le même réseau.
J'ai activé tout le nécessaire pour qu'ils puissent communiquer avec winrm.

Lorsque j'exécute la commande suivante:

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

Cela fonctionne correctement, mais le programme n'est jamais vu sur la machine distante. Pour autant que je sache, c'est un comportement attendu.

Je suppose que le processus démarre correctement, puis est immédiatement fermé à la fin de la session. Comment exécuter le programme pour qu'il apparaisse sur la machine hôte?

7
Trevor Hickey

De par leur conception, vous n'êtes pas vraiment censé pouvoir lancer des processus dans les sessions d'autres personnes.

(pour clarifier, même si vous êtes connecté de manière interactive sur un bureau d'ordinateur et que vous avez également une autre connexion réseau distincte sur la même machine en même temps en utilisant les mêmes informations d'identification, celles-ci comptent toujours comme deux sessions de connexion différentes.)

C'est tout simplement contraire au modèle de sécurité de Windows lui-même et les tentatives de le renverser seront mal vues. Il est donc peu probable que vous trouviez un moyen facile et supportable de le faire. C'est techniquement possible, mais cela implique de s'exécuter en tant que système local, de copier un autre jeton de sécurité d'un utilisateur connecté et de lancer un processus avec cet autre jeton. Vous auriez besoin de l'API Windows pour cela, ce qui est à peu près la seule chose dans laquelle Powershell n'est pas très bon. Voir WTSQueryUserToken et CreateProcessAsUser dans l'API Windows pour plus de détails à ce sujet.

Une autre idée, afin de ne pas faire pipi totalement dans vos Cheerios, vous pourriez être en mesure d'accomplir cela en créant à distance une tâche planifiée qui lance le processus. Voir http://blogs.technet.com/b/heyscriptingguy/archive/2005/09/06/how-can-i-remotely-start-an-interactive-process.aspx pour plus d'informations sur ça.

Edit: Oh, et j'ai oublié ... assez sûr PsExec avec le -i le paramètre peut le faire. Vous devez fournir l'ID de session d'ouverture de session. Et avoir les autorisations pour le faire. Il utilise probablement la même API Windows que celle que j'ai mentionnée, ce qui tire parti du fait que PsExec installe un service temporaire qui s'exécute en tant que système local.

10
Ryan Ries

J'ai pu obtenir ce travail en utilisant PsExec comme mentionné dans une autre réponse.

  1. Télécharger PSTools
  2. Décompressez vers C:\Windows\PSTools
  3. Ajoutez C:\Windows\PSTools À votre CHEMIN
  4. Obtenir l'ID de processus de la session RDP (tasklist fonctionnera, ou une ligne unique fantaisie: $session = tasklist /fo CSV | findstr RDP ; $session = $session.Split(",")[3] ; $session.Split('"')[1])
  5. Processus de démarrage: PsExec.exe -s -i 123 calc.exe ("123" étant l'ID de session RDP)

Voici comment je le fais avec 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
6

Vous pouvez créer un "hook appelable" sur la machine distante: il s'agit d'une tâche planifiée définie pour "s'exécuter uniquement lorsque l'utilisateur est connecté", affectée à l'exécution sous le compte de l'utilisateur qui sera connecté lors de l'exécution. L'action de la tâche est l'exécutable que vous souhaitez exécuter.

Les tâches planifiées peuvent être créées à distance via powershell ou schtasks, puis appelées simplement par le "nom" de la tâche elle-même à l'aide de schtasks ou de Start-ScheduledTask de powershell.

  1. Sur la machine distante, créez une tâche planifiée barebones exécutée par l'utilisateur qui exécute la session en cours.
  2. Définissez la tâche pour qu'elle s'exécute "uniquement lorsque l'utilisateur est connecté"
  3. Si le fichier .exe ou l'élément dans l'onglet "Action" de la tâche planifiée a "Exécuter en tant qu'administrateur" défini sur l'élément du système de fichiers (clic droit, propriétés, Compatibilité> Exécuter en tant qu'administrateur), la tâche planifiée doit être exécutée avec un niveau élevé privilèges ainsi ou il échouera ou n'apparaîtra pas.
  4. L'auteur de la tâche planifiée doit avoir des privilèges d'administrateur, de sorte que lorsqu'il est appelé à distance, vous pouvez utiliser ce compte administrateur pour appeler une tâche planifiée qui est ensuite exécutée sur le profil utilisateur spécifié sous "Exécuter uniquement lorsque l'utilisateur est connecté".
  5. Assurez-vous que la machine est connectée en tant que cet utilisateur.
  6. Cela peut dépendre de l'application si cette tâche s'exécute correctement si la machine est verrouillée. D'après mon expérience, c'est le cas.
  7. À partir de là, vous pouvez utiliser schtasks.exe et appeler le nom de la tâche planifiée avec le nom d'hôte et transmettre les informations d'identification du compte élevé utilisé pour créer la tâche planifiée (pas l'utilisateur qui sera connecté).
  8. Vous pouvez également l'appeler dans PowerShell si la machine distante exécute une version PowerShell qui prend en charge Start-ScheduledTask.

Pour appeler la tâche, vous référencez la tâche par le nom que vous lui avez donné:

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

La création d'une tâche planifiée à distance est possible avec schtasks.exe ou New-ScheduledTaskPrincipal dans powershell. Si l'exécutable ou l'élément "Action" de la tâche est marqué comme "exécuté en tant qu'administrateur" sur le système de fichiers, la tâche nécessitera une information d'identification New-ScheduledTaskPrincipal à joindre lors de la création de la tâche afin de définir cette propriété de manière appropriée.

L'utilisateur actuellement connecté peut être une cible mobile, bien qu'il puisse être interrogé avec Get-LoggedOnUser via PowerShell avant la création de la tâche planifiée elle-même.

Un code détaillé de ce type est à venir dans les prochaines 48 heures, je voulais mettre la structure de base à la disposition de tous.

4

Si vous voulez éviter le RDP pour obtenir l'ID de processus dans la réponse de Victor, vous pouvez le faire en appelant query session commande sur la machine distante. Exemple de script 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]
1
Ankit Aggarwal