A utility for non-admin users to connect to RDP sessions in WinServer 2012R2.

The problem during the quarantine work of the enterprise became the following: it is really necessary to minimize the number of visits to specialists' offices who provide support and consultation on application software. To be frank, users often take advantage of specialists' help without wanting to delve into the issue, saying, 'They'll come β€” they'll help β€” they'll fix it, and I'll just have a smoke or a coffee in the meantime.' Telephone consultation with joint access to the server is more effective when viewing the remote screen.

A utility for non-admin users to connect to RDP sessions in WinServer 2012R2.

After the 'invention' of our bicycle, sensible information on the topic of the article emerged: RDS Shadow – shadow connection to RDP sessions of users in Windows Server 2012 R2 or Shadow mode of a non-administrative user in Windows Server or Delegating management of RDP sessions. All of them imply the use of the console, even with elements of simple dialogue.

The information presented below is intended for those who can normally tolerate abnormal perversions to achieve the desired result while inventing unnecessary methods.
To 'not drag the cat by the tail', I'll start with the last point: the bicycle works for the regular user using the utility AdmiLink, for which the author deserves thanks.

I. Console and Shadow RDP.

Since the use of the Server Manager console with administrative rights -> QuickSessionCollection -> by clicking on the session of the user of interest, selecting Shadow (Shadow Copy) from the context menu for staff instructing on software usage, β€” was not an option, another 'wooden' method was considered, namely:

1. We find out the RDP session ID:

query user | findstr Administrator

or:

qwinsta | findstr Administrator 

Moreover, '| findstr Administrator' was only convenient when you know exactly what you need, or to use only the first part to see all users logged into the server. The administrator 2. We connect to this session, provided that in the domain

A utility for non-admin users to connect to RDP sessions in WinServer 2012R2.

group policies the parameter 'Establishes rules for remote control of user sessions of remote desktop services' is chosen with the option at least 'Monitoring session with user permission' ( mstsc /shadow:127more details):

Please note that the list will only show user logins.

I repeat that without administrative rights you will get the following:

I would like to reiterate that without administrative rights, you will receive the following:

A utility for non-admin users to connect to RDP sessions in WinServer 2012R2.

However, for the preliminary debugging of the program in question, I used an account with administrative rights.

II. Program

So, the task is set: to create a simple graphical interface for connecting to the user's shadow sense with their permission and sending a message to the user. The programming environment chosen is Lazarus.

1. We obtain a complete domain list of users "login" β€” "full name" from the administrator or again via the console:

wmic useraccount get Name,FullName 

no one forbids this approach either:

wmic useraccount get Name,FullName > c:testusername.txt

I should mention that Lazarus had a problem handling this file, as its default encoding is UCS-2, so I had to manually convert it to regular UTF-8. The file structure has many tabs or, rather, a multitude of spaces, which we decided to process programmatically; sooner or later, the encoding issue will be resolved, and the file will be updated programmatically.

Thus, in the concept, there's a folder accessible to program users, for example c:test, which will contain 2 files: the first with login and fullname, the second with id_rdp and user logins. We will process this data as best we can:).

For now, in order to associate it with the session list, we transfer this (login and fullname) content into an array:

procedure Tf_rdp.UserF2Array;
var 
  F:TextFile;   i:integer;   f1, line1:String;   fL: TStringList;
begin  //f_d global path to file storage
f1:=f_d+'user_name.txt';     //task is to read the file content into the array
fL := TStringList.Create; //we will subject the string to transformations with delimiters
fL.Delimiter := '|'; fL.StrictDelimiter := True;
AssignFile(F,f1); 
try // Open the file for reading
  reset(F); ReadLn(F,line1);
  i:=0;
while not eof(F) do // Read lines until the end of the file
begin
ReadLn(F,line1);
line1:= StringReplace(line1, '  ', '|',[]); //replace the first 2 spaces with the delimiter |
// remove all double spaces
while pos('  ',line1)>0 do line1:= StringReplace(line1, '  ', ' ', [rfReplaceAll]);
begin
if (pos('|',line1)>0) then
begin //if the delimiter exists, add it to the array
fL.DelimitedText :=line1; // split into columns
if (fL[0] '') then //if the account has a name
begin //add it to the array
 inc(i); // eliminate possible single spaces in the login
 fam[0,i]:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]);
 fam[1,i]:=fL[0];
 end;end;end;end; // Done. Close the file.
 CloseFile(F);
 Fl.Free;
 except
 on E: EInOutError do  ShowMessage('Error processing file. Details: '+E.Message);
 end;end;

I apologize for the "amount of code"; the following points will be more concise.

2. Similarly to the method from the previous point, we read the processing result of the list into a StringGrid element, while providing a 'significant' piece of code:

2.1 Get the current list of RDP sessions into a file:

f1:=f_d+'user.txt';
cmdline:='\/c query user >'+ f1;
if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1)=0 then;
Sleep(500); \/\/ you can wait longer while the file is being created for reading

2.2 Process the file (only significant lines of code are indicated):

StringGrid1.Cells[0,i]:=fL[1]; StringGrid1.Cells[2,i]:=fL[3]; \/\/ iterating into StringGrid1
login1:=StringReplace(fL[1],' ','',[rfReplaceall, rfIgnoreCase]); \/\/ removing spaces from the login
if (SearchArr(login1)>=0) then \/\/ searching in the array from p1. login and recording in the table the full name
StringGrid1.Cells[1,i]:=fam[1,SearchArr(login1)]
else StringGrid1.Cells[1,i]:='+'; \/\/ or recording a plus :)
.... \/\/ depending on the user's choice, sort and format according to the data
if (b_id.Checked=true) then SortGrid(0) else SortGrid(1);
StringGrid1.AutoSizeColumn(0);StringGrid1.AutoSizeColumn(1); StringGrid1.AutoSizeColumn(2);  

3. Directly connecting when clicking on the row with the user and the number of their session:

  id:=(StringGrid1.Row);\/\/ getting the row number  IntToStr(StringGrid1.Row)
  ids:=StringGrid1.Cells[2,id]; \/\/ getting the rdp identifier
  cmdline:='\/c mstsc \/shadow:'+ ids; \/\/ and connecting....
 if (b_rdp.Checked=True) then  if ShellExecute(0,nil, PChar('cmd'),PChar(cmdline),nil,1) =0 then;       

4. A couple of additional enhancements have been made, such as sorting by clicking on the radio button, and messages to the user or all users.

A utility for non-admin users to connect to RDP sessions in WinServer 2012R2.

β†’ The full source code can be viewed here

III. Application of AdminLink β€” what I observed:

AdminLink indeed generates a shortcut that references the location of the utility admilaunch.exe, and a personal copy of the launch utility AdmiRun.Exe which is located in the user's folder, for example vasya, similar to C:\Users\vasya\WINDOWS. Overall, it’s not as bad: with the file shortcut access rights and others, you can play around to clear your administrative conscience.

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers πŸ”₯ Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster