Le problÚme pendant la période de confinement de l'entreprise a été le suivant : il est vraiment nécessaire de minimiser le nombre de visites des spécialistes en charge du support et des conseils sur les logiciels applicatifs. Entre nous, les utilisateurs abusent souvent de l'aide des spécialistes, préférant dire "ils viendront, aideront, feront, pendant que je fume/bois un café, etc.". Une consultation par téléphone avec un accÚs partagé au serveur est plus efficace lorsqu'on visualise l'écran à distance.

Juste aprĂšs l'"invention" de notre vĂ©lo, des informations pertinentes sur le sujet de l'article sont apparues : ou ou . Tous impliquent l'utilisation de la console, mĂȘme avec des Ă©lĂ©ments de dialogue simples.
Toutes les informations ci-dessous sont destinées à ceux qui supportent normalement des perversions anormales pour obtenir le résultat souhaité en trouvant des méthodes inutiles.
Pour "ne pas faire traßner les choses", je commencerai par le dernier : le vélo fonctionne pour l'utilisateur ordinaire grùce à l'utilitaire , merci à son auteur.
I. Console et shadow RDP.
Puisque l'utilisation de la console Server Manager avec des droits admin -> QuickSessionCollection -> en cliquant sur la session de l'utilisateur concerné, en choisissant dans le menu contextuel Shadow (Copie FantÎme) pour le personnel instruisant sur l'utilisation du logiciel, ce n'était pas une option, une autre méthode "rustique" a été considérée, à savoir :
1. Obtenez l'ID de session RDP :
query user | findstr Administratorou :
qwinsta | findstr Administrator Le "| findstr Administrator" n'était pratique que lorsque vous savez exactement que vous avez besoin de Administrator , ou d'utiliser uniquement la premiÚre partie pour voir tous les utilisateurs connectés sur le serveur.
![]()
2. Connectez-vous à cette session, à condition que dans les politiques de groupe de domaine l'option "Définit les rÚgles de gestion à distance pour les sessions utilisateur des services de Bureau à distance" soit configurée sur au moins "Surveillance de la session avec l'autorisation de l'utilisateur" ():
mstsc /shadow:127Veuillez noter que seule les identifiants des utilisateurs seront visibles dans la liste.
Je répÚte qu'en l'absence de droits admin, vous obtiendrez ce qui suit :

Mais pour le débogage préliminaire du programme dont nous allons parler, j'ai utilisé un compte avec des droits d'administrateur.
II. Programme
Ainsi, la tùche est la suivante : créer une interface graphique simple pour se connecter à un capteur secondaire de l'utilisateur avec son autorisation, et envoyer un message à l'utilisateur. L'environnement de programmation sélectionné est Lazarus.
1. Obtenir la liste complĂšte des utilisateurs « login » â « nom complet » de l'administrateur, ou encore via la console :
wmic useraccount get Name,FullName personne n'interdit mĂȘme ainsi :
wmic useraccount get Name,FullName > c:testusername.txtJe dois dire tout de suite que c'est avec Lazarus que j'ai rencontré des problÚmes pour traiter ce fichier, car par défaut son encodage est UCS-2, donc j'ai dû le convertir manuellement en UTF-8 standard. La structure du fichier contient beaucoup de tabulations, ou plutÎt de nombreux espaces, qui ont finalement été programmatiquement traités ; tÎt ou tard, le problÚme d'encodage sera résolu, et le fichier sera mis à jour par programme.
Ainsi, dans le projet, il y a un dossier accessible aux utilisateurs du programme, par exemple c:test, qui contiendra 2 fichiers : le premier avec login et nom complet, le second avec id_rdp et login des utilisateurs. Ensuite, nous traitons ces données comme nous le pouvons :)).
Pour l'instant, afin d'associer à la liste des sessions, nous transférons ce contenu (login et nom complet) dans un tableau :
procedure Tf_rdp.UserF2Array;
var
F:TextFile; i:integer; f1, line1:String; fL: TStringList;
begin //f_d chemin global vers l'emplacement des fichiers
f1:=f_d+'user_name.txt'; //l'objectif est de lire le contenu du fichier dans un tableau
fL := TStringList.Create; // nous allons soumettre la ligne à des métamorphoses avec des séparateurs
fL.Delimiter := '|'; fL.StrictDelimiter := True;
AssignFile(F,f1);
try // Ouvrir le fichier pour lecture
reset(F); ReadLn(F,line1);
i:=0;
while not eof(F) do // Lire les lignes jusqu'Ă la fin du fichier
begin
ReadLn(F,line1);
line1:= StringReplace(line1, ' ', '|',[]); // remplacer les premiers espaces par le séparateur |
// supprimer tous les doubles espaces
while pos(' ',line1)>0 do line1:= StringReplace(line1, ' ', ' ', [rfReplaceAll]);
begin
if (pos('|',line1)>0) then
begin // si le séparateur existe, l'enregistrer dans le tableau
fL.DelimitedText :=line1; // division en colonnes
if (fL[0]'') then // si le compte a un nom
begin // l'enregistrer dans le tableau
inc(i); // éliminer les éventuels espaces uniques dans le login
fam[0,i]:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]);
fam[1,i]:=fL[0];
end;end;end;end; // PrĂȘt. Fermer le fichier.
CloseFile(F);
Fl.Free;
except
on E: EInOutError do ShowMessage('Erreur de traitement du fichier. Détails : '+E.Message);
end;end;Je m'excuse pour le « beaucoup de code », les points suivants seront plus concis.
2. De la mĂȘme maniĂšre qu'avec la mĂ©thode du point prĂ©cĂ©dent, nous lisons le rĂ©sultat du traitement de la liste dans l'Ă©lĂ©ment StringGrid, tout en fournissant un extrait « significatif » de code :
2.1 Récupérer la liste actuelle des sessions RDP dans un fichier :
f1:=f_d+'user.txt';
cmdline:='\/c query user >'+ f1;
if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1)=0 then;
Sleep(500); \/\/ on peut attendre plus longtemps pendant que le fichier pour lecture est créé2.2 Traitement du fichier (seules les lignes de code significatives sont indiquées) :
StringGrid1.Cells[0,i]:=fL[1]; StringGrid1.Cells[2,i]:=fL[3]; \/\/ ajoutons en boucle dans StringGrid1
login1:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]); \/\/ supprimons les espaces du login
if (SearchArr(login1)>=0) then \/\/ cherchons dans le tableau du point 1. login et enregistrons dans le tableau le nom et prénom
StringGrid1.Cells[1,i]:=fam[1,SearchArr(login1)]
else StringGrid1.Cells[1,i]:='+'; \/\/ sinon, nous mettons un plus :)
.... \/\/ selon le choix de l'utilisateur, nous trions et formatons les données
if (b_id.Checked=true) then SortGrid(0) else SortGrid(1);
StringGrid1.AutoSizeColumn(0);StringGrid1.AutoSizeColumn(1); StringGrid1.AutoSizeColumn(2); 3. La connexion elle-mĂȘme lors du clic sur la ligne de l'utilisateur et le numĂ©ro de sa session :
id:=(StringGrid1.Row);\/\/ nous découvrons le numéro de ligne IntToStr(StringGrid1.Row)
ids:=StringGrid1.Cells[2,id]; \/\/ nous obtenons l'identifiant rdp
cmdline:='\/c mstsc \/shadow:'+ ids; \/\/ et nous nous connectons....
if (b_rdp.Checked=True) then if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1) =0 then; 4. Quelques embellissements ont également été ajoutés, comme le tri au clic sur le bouton radio, et les messages à l'utilisateur, ou à tous les utilisateurs.

â Le code source complet peut ĂȘtre vu
III. Application d'AdminLink â ce que j'ai observĂ© :
AdminLink génÚre effectivement un raccourci, qui fait référence à l'emplacement de l'utilitaire admilaunch.exe, et une copie personnelle de l'utilitaire de lancement AdmiRun.Exe qui se trouve dans le dossier de l'utilisateur, par exemple vasya, de type C:UsersvasyaWINDOWS. En gros, ce n'est pas si mal : avec les droits d'accÚs au fichier du raccourci et d'autres, pour apaiser ma conscience d'administrateur, on peut jouer.
Source : habr.com
