Problemi gjatë periudhës së karantinës në ndërmarrje doli në vijim: me të vërtetë është e nevojshme të minimizohet numri i vizitave në zyrat e specialistëve që ofrojnë mbështetje dhe konsultime për softuerin aplikativ, dhe për ta thënë hapur, përdoruesit shpesh abuzojnë me ndihmën e specialistëve pa dëshiruar të merret me vetë çështjen, thonë 'do të vijnë — do të ndihmojnë — do ta bëjnë, ndërkohë unë do pi një kafe'. Konsultimi telefonik me akses të përbashkët në server është më i efektshëm kur shikohet ekranin e distancuar.

Vetëm pas 'shpikjes' së biçikletës tonë, u paraqit një informacion i arsyeshëm mbi temën e artikullit: ose ose . Të gjitha këto nënkuptojnë përdorimin e konsolës, madje me elemente të dialogut të thjeshtë.
Të gjitha informacionet e paraqitura më poshtë janë për ata që normalisht durojnë devijimet e çuditshme për të arritur rezultatin e dëshiruar, duke shpikur mënyra të panevojshme.
Për të mos e zgjatur bisedën, do të filloj me të fundit: bicikleta funksionon me një mjet te përdoruesi i zakonshëm. , për të cilin i falënderojmë autorin.
I. Konsola dhe shadow RDP.
Duke qenë se përdorimi me të drejtat administrative të konsolës Server Manager -> QuickSessionCollection -> duke klikur mbi sesionin e përdoruesit që ju intereson, duke zgjedhur në menunë e kontekstit Shadow (Kopja Hije) për stafin që udhëheq punën me softuerin, — nuk është një opsion, u shqyrtua një tjetër metodë "drunore", dmth:
1. Mësojmë ID-në e sesionit RDP:
query user | findstr Administratorose:
qwinsta | findstr Administrator Kështu që "| findstr Administrator" ishte e dobishme vetëm kur e di se çfarë Administrator të duash, ose të përdorësh vetëm pjesën e parë për të parë të gjithë ata që janë loguar në server.
![]()
2. Lidhemi me këtë sesion, me kusht që në politikën grupore të domenit parametri "Establishes remote management rules for Remote Desktop Services user sessions" të ketë zgjedhur të paktën "Monitoring the session with user permission" ( mstsc /shadow:127):
Ju lutem vini re se në listë do të jenë vetëm emrat e përdoruesve.Прошу обратить внимание что в списке будут только логины пользователей.
Për t'u përsëritur, pa të drejtat administrative do të merrni sa vijon:

Por për debugin paraprak të programit, për të cilin do flasim, kam përdorur një llogari me të drejta administrative.
II. Programi
Pra, detyra: krijimi i një ndërfaqe grafike të thjeshtë për lidhjen me sensorin e errët të përdoruesit me lejen e tij, dërgimi i një mesazhi përdoruesit. Ambienti i programimit është përzgjedhur Lazarus.
1. Merrni listën e plotë të domeneve të përdoruesve "login" - "emri i plotë" nga admini, ose përsëri përmes konsolës:
wmic useraccount get Name,FullName askush nuk e ndalon të bëhet edhe kështu:
wmic useraccount get Name,FullName > c:testusername.txtTë them të drejtën, që në Lazarus kishte një problem me përpunimin e këtij skedari, sepse kodeka e tij e paracaktuar është UCS-2, prandaj duhej ta konvertoja manually në UTF-8 të zakonshëm. Në strukturën e skedarit ka shumë tabulime, më saktësisht shumë hapësira, të cilat vendosëm t'i përpunojmë programatikisht, herët a vonë problemi me kodekën do zgjidhet dhe skedari do azhurnohet programatikisht.
Pra fillimi, mendoni se ka një folder, i cili do të jetë në dispozicion për përdoruesit e programit, për shembull c:test, ku do të jenë 2 skedarë: i pari me login dhe emër të plotë, dhe i dyti me id_rdp dhe login e përdoruesve. Pastaj këto të dhëna i trajtojmë siç dimë:).
Deri atëherë, për t'i lidhur me listën e seancave, do ta transferojmë këtë (login dhe emër të plotë) përmbajtje në një array:
procedura Tf_rdp.UserF2Array;
var
F:TextFile; i:integer; f1, line1:String; fL: TStringList;
begin //f_d rrugë globale për vendosjen e skedave
f1:=f_d+'user_name.txt'; //detyra është të lexoni përmbajtjen e skedës në një array
fL := TStringList.Create; // do t'i nënshtrohemi ndryshimeve të ndarjes në vargje
fL.Delimiter := '|'; fL.StrictDelimiter := True;
AssignFile(F,f1);
try // Hap skedën për lexim
reset(F); ReadLn(F,line1);
i:=0;
while not eof(F) do // Lexojmë rreshtat, sa herë që skeda të mos përfundojë
begin
ReadLn(F,line1);
line1:= StringReplace(line1, ' ', '|',[]); //zëvendësojmë hapësirat e para me ndarës |
// heqim të gjitha hapësirat e dyfishta
while pos(' ',line1)>0 do line1:= StringReplace(line1, ' ', ' ', [rfReplaceAll]);
begin
if (pos('|',line1)>0) then
begin //nëse ndarësi ekziston, e vendosim atë në array
fL.DelimitedText :=line1; // e ndjekim në kolona
if (fL[0] '') then //nëse llogaria ka emër
begin //e vendosim atë në array
inc(i); // heqim hapësirat e mundshme të vetme në emrin
fam[0,i]:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]);
fam[1,i]:=fL[0];
end;end;end;end; // Gati. Mbyllim skedën.
CloseFile(F);
Fl.Free;
except
on E: EInOutError do ShowMessage('Gabim gjatë përpunimit të skedës. Detajet: '+E.Message);
end;end;Më vjen keq për "shumë kod", pikat e ardhshme do të jenë më të shkurtra.
2. Po të njëjtën mënyrë si në pikën e mëparshme, lexojmë rezultatin e përpunimit të listës në elementin StringGrid, teksa sjell një pjesë "të rëndësishme" të kodit:
2.1 Marrim listën aktuale të sesioneve RDP në një skedar:
f1:=f_d+'user.txt';
cmdline:='/c query user >'+ f1;
if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1)=0 then;
Sleep(500); // mund të presim më gjatë derisa skedari krijohet për lexim2.2 Përpunojmë skedarin (shtohen vetëm rreshtat e rëndësishëm të kodit):
StringGrid1.Cells[0,i]:=fL[1]; StringGrid1.Cells[2,i]:=fL[3]; //shtojmë në cikël në StringGrid1
login1:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]); //heqim hapësirat nga login-i
if (SearchArr(login1)>=0) then //kërkojmë në masivin e p1. loginin dhe regjistrojmë në tabelë FIO
StringGrid1.Cells[1,i]:=fam[1,SearchArr(login1)]
else StringGrid1.Cells[1,i]:='+'; // ose regjistrojmë një plus:)
.... //sipas zgjedhjes së përdoruesit, rendisim dhe formatojmë sipas të dhënave
if (b_id.Checked=true) then SortGrid(0) else SortGrid(1);
StringGrid1.AutoSizeColumn(0);StringGrid1.AutoSizeColumn(1); StringGrid1.AutoSizeColumn(2); 3. Pjesa e lidhjes direkt kur klikohet në rreshtin me përdoruesin dhe numrin e sesionit të tij:
id:=(StringGrid1.Row);// marrim numrin e rreshtit IntToStr(StringGrid1.Row)
ids:=StringGrid1.Cells[2,id]; //marrim identifikuesin rdp
cmdline:='/c mstsc /shadow:'+ ids; //dhe lidhemi....
if (b_rdp.Checked=True) then if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1) =0 then; 4. Është bërë edhe disa dekorime, si renditja me klikimin mbi radiobutton dhe mesazhet për përdoruesin, ose për të gjithë përdoruesit.

→ Kodi burimor i plotë mund të shihet
III. Përdorimi i AdminLink — çfarë kam parë:
AdminLink vërtet gjeneron një shkurtesë që lidhet me vendndodhjen e utilitarit admilaunch.exe, dhe kopja personale e utilitarit AdmiRun.Exe e cila ndodhet në dosjen e përdoruesit, për shembull vasya, në stilin e C:UsersvasyaWINDOWS. Në përgjithësi, nuk është aq keq: me të drejtat e aksesit në skedarin e shkurtesës dhe të tjera, për të pastruar ndërgjegjen time si administrator, mund të luaj me to.
Burimi: habr.com
