Das Problem während der Quarantänezeit des Unternehmens war folgendes: Es ist wirklich notwendig, die Anzahl der Besuche in den Büros der Fachleute, die Beratungen zum Anwendungssoftware anbieten, zu minimieren. Außerdem müssen wir ehrlich sagen, dass die Benutzer oft die Hilfe der Fachleute ausnutzen, ohne sich mit den Fragen wirklich auseinanderzusetzen, sie denken: "Sie kommen — helfen — machen, und ich kann währenddessen eine rauchen oder einen Kaffee trinken." Eine telefonische Beratung beim gemeinsamen Zugriff auf den Server ist effektiver, wenn der Remote-Bildschirm angesehen wird.

Bereits nach der "Erfindung" unseres Rades erschien sinnvolle Information zu dem Thema des Artikels: oder oder . Sie alle setzen die Nutzung der Konsole voraus, sogar mit Elementen eines einfachen Dialogs.
Alle unten aufgeführten Informationen sind für diejenigen gedacht, die normalerweise mit abnormalen Abweichungen umgehen können um das gewünschte Ergebnis zu erzielen, indem sie unnötige Methoden erfinden.
Um "nicht den Kater am Schwanz zu ziehen", beginne ich mit dem Letzten: Das Fahrrad funktioniert beim normalen Benutzer mit Hilfe des Dienstprogramms , dafür ein Dankeschön an den Autor.
I. Konsole und Shadow RDP.
Da die Nutzung der Konsole des Servermanagers mit administrativen Rechten -> QuickSessionCollection -> durch Klicken auf die Sitzung des gewünschten Benutzers und Auswahl von Shadow (Schattenkopie) für das Personal, das in der Nutzung der Software anweist, war keine Option, daher wurde eine andere "holprige" Methode in Betracht gezogen:
1. Wir erfahren die RDP-Sitzungs-ID:
query user | findstr Administratoroder:
qwinsta | findstr Administrator Dabei war "| findstr Administrator" nur praktisch, wenn man weiß, dass genau das Administrator benötigt wird oder man nur den ersten Teil nutzt, um alle eingeloggten Benutzer auf dem Server zu sehen.
![]()
2. Wir verbinden uns mit dieser Sitzung, vorausgesetzt in den Domänen- Gruppenrichtlinien ist die Einstellung "Legt die Regeln für die Remoteverwaltung der Benutzersitzungen des Remote Desktop Services fest" mindestens auf "Überwachung der Sitzung mit Genehmigung des Benutzers" eingestellt ():
mstsc /shadow:127Bitte beachten Sie, dass in der Liste nur Benutzeranmeldungen angezeigt werden.
Ich wiederhole, dass Sie ohne administrative Rechte folgendes erhalten werden:

Für die vorläufige Fehlersuche des zu behandelnden Programms habe ich ein Konto mit Administratorrechten verwendet.
II. Programm
Die Aufgabenstellung lautet: Erstellung einer einfachen grafischen Oberfläche zur Verbindung mit dem Shadow-Sensor des Benutzers mit dessen Zustimmung und zum Versenden einer Nachricht an den Benutzer. Die Programmierumgebung wurde auf Lazarus gewählt.
1. Erhalten Sie die vollständige Domänenliste der Benutzer "Login" - "Vollständiger Name" vom Administrator oder erneut über die Konsole:
wmic useraccount get Name,FullName Niemand hindert Sie daran, es auch so zu tun:
wmic useraccount get Name,FullName > c:testusername.txtIch möchte gleich sagen, dass Lazarus Probleme bei der Verarbeitung dieser Datei hatte, da sie standardmäßig in der Kodierung UCS-2 vorliegt. Daher musste sie manuell in das gängige UTF-8 umgewandelt werden. Die Struktur der Datei enthält viele Tabulatoren, genauer gesagt viele Leerzeichen, die beschlossen wurden, trotzdem programmgesteuert zu verarbeiten. Früher oder später wird das Problem mit der Kodierung gelöst, und die Datei wird programmgesteuert aktualisiert.
Die Idee ist, einen Ordner zur Verfügung zu stellen, der für die Benutzer des Programms zugänglich ist, z.B. c:test, in dem sich zwei Dateien befinden: die erste mit Login und Vollständigem Namen, die zweite mit ID_RDP und Login der Benutzer. Diese Daten werden dann bearbeitet, wie wir können:).
Um es mit der Sitzungsliste zu verknüpfen, übertragen wir den Inhalt (Login und Vollständiger Name) in ein Array:
procedure Tf_rdp.UserF2Array;
var
F:TextFile; i:integer; f1, line1:String; fL: TStringList;
begin //f_d globaler Pfad zur Ablage der Dateien
f1:=f_d+'user_name.txt'; // Aufgabe besteht darin, den Inhalt der Datei in ein Array zu lesen
fL := TStringList.Create; // die Zeile wird Metamorphosen mit Trennzeichen unterzogen
fL.Delimiter := '|'; fL.StrictDelimiter := True;
AssignFile(F,f1);
try // Datei zum Lesen öffnen
reset(F); ReadLn(F,line1);
i:=0;
while not eof(F) do // Zeilen lesen, bis das Ende der Datei erreicht ist
begin
ReadLn(F,line1);
line1:= StringReplace(line1, ' ', '|',[]); // ersetzt das erste gefundene Doppelleerzeichen mit dem Trennzeichen |
// entfernt alle doppelten Leerzeichen
while pos(' ',line1)>0 do line1:= StringReplace(line1, ' ', ' ', [rfReplaceAll]);
begin
if (pos('|',line1)>0) then
begin // wenn das Trennzeichen existiert, fügen Sie es in das Array ein
fL.DelimitedText :=line1; // zerlegen in Spalten
if (fL[0]'' ) then // wenn das Konto einen Namen hat
begin // fügt es in das Array ein
inc(i); // entfernt mögliche einzelne Leerzeichen im Login
fam[0,i]:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]);
fam[1,i]:=fL[0];
end;end;end;end; // Fertig. Datei schließen.
CloseFile(F);
Fl.Free;
except
on E: EInOutError do ShowMessage('Fehler bei der Verarbeitung der Datei. Details: '+E.Message);
end;end;Ich bitte um Entschuldigung für den "vielen Code", die nächsten Punkte werden prägnanter sein.
2. Entsprechend der Methode aus dem vorherigen Punkt lesen wir das Ergebnis der Verarbeitung der Liste in das Element StringGrid ein, dabei bringe ich einen "bedeutenden" Code-Ausschnitt:
2.1 Wir erhalten die aktuelle Liste der RDP-Sitzungen in eine Datei:
f1:=f_d+'user.txt';
cmdline:='\/c query user >'+ f1;
if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1)=0 then;
Sleep(500); \/\/ man kann auch länger warten, während die Datei zur Lesung erstellt wird2.2 Wir verarbeiten die Datei (es werden nur wesentliche Codezeilen angegeben):
StringGrid1.Cells[0,i]:=fL[1]; StringGrid1.Cells[2,i]:=fL[3]; \/\/ wir fügen in der Schleife in StringGrid1 ein
login1:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]); \/\/ wir entfernen Leerzeichen aus dem Login
if (SearchArr(login1)>=0) then \/\/ wir suchen im Array aus P1. das Login und schreiben es in die Tabelle FIO
StringGrid1.Cells[1,i]:=fam[1,SearchArr(login1)]
else StringGrid1.Cells[1,i]:='+'; \/\/ oder wir schreiben ein Pluszeichen:)
.... \/\/ je nach Wahl des Nutzers sortieren und formatieren wir die Daten
if (b_id.Checked=true) then SortGrid(0) else SortGrid(1);
StringGrid1.AutoSizeColumn(0);StringGrid1.AutoSizeColumn(1); StringGrid1.AutoSizeColumn(2); 3. Direkt die Verbindung bei einem Klick auf die Zeile mit dem Nutzer und der Nummer seiner Sitzung:
id:=(StringGrid1.Row);\/\/ wir erfahren die Zeilennummer IntToStr(StringGrid1.Row)
ids:=StringGrid1.Cells[2,id]; \/\/ wir erhalten die RDP-ID
cmdline:='\/c mstsc \/shadow:'+ ids; \/\/ und verbinden uns....
if (b_rdp.Checked=True) then if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1) =0 then; 4. Es sind noch ein paar Verschönerungen wie die Sortierung durch einen Klick auf den Radiobutton und Nachrichten an den Nutzer oder alle Nutzer gemacht worden.

→ Den vollständigen Quellcode kann man sehen
III. Anwendung von AdminLink – was ich gesehen habe:
AdminLink generiert tatsächlich eine Verknüpfung, die auf den Speicherort des Tools verweist admilaunch.exe, und einer persönlichen Kopie des Starttools AdmiRun.Exe , die sich im Benutzerordner befindet, zum Beispiel vasya, entsprechend C:UsersvasyaWINDOWS. Im Großen und Ganzen ist nicht alles so schlecht: Mit dem Zugriffsrecht auf die Datei der Verknüpfung und anderen Aspekten kann man zum eigenen administischen Gewissen spielen.
Quelle: habr.com
